I am converting an old Objective-C class into Swift. My actual question is at the very end after all of the code.
Here is a cut-down version of the Objective-C class:
DateInfo.h:
#import <Foundation/Foundation.h>
@interface RMYearInfo : NSObject
// There are also some instance properties but those aren't relevant to the question
+ (NSInteger)numberOfMonths;
+ (NSArray *)shortMonthNames;
+ (NSArray *)longMonthNames;
+ (NSInteger)firstWeekday;
// several other class methods
@end
DateInfo.m:
#import "DateInfo.h"
static NSArray *shortMonthNames = nil;
static NSArray *longMonthNames = nil;
static NSInteger firstWeekday;
// there are several other statics as well
@implementation DateInfo
+ (void)reinitialize {
NSCalendar *cal = [NSCalendar currentCalendar];
firstWeekday = [cal firstWeekday] - 1;
NSDateFormatter *yearFormatter = [[NSDateFormatter alloc] init];
NSArray *shortMonths = [yearFormatter shortStandaloneMonthSymbols];
NSArray *longMonths = [yearFormatter standaloneMonthSymbols];
NSMutableArray *upperShortMonths = [[NSMutableArray alloc] initWithCapacity:shortMonths.count];
NSMutableArray *upperLongMonths = [[NSMutableArray alloc] initWithCapacity:shortMonths.count];
for (NSString *name in shortMonths) {
[upperShortMonths addObject:[name uppercaseString]];
}
for (NSString *name in longMonths) {
[upperLongMonths addObject:[name uppercaseString]];
}
shortMonthNames = [upperShortMonths copy];
longMonthNames = [upperLongMonths copy];
NSLocale *locale = [NSLocale current];
// lots of other processing for other statics
// based on yearFormatter, locale, and cal
}
+ (void)initialize {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reinitialize) name:NSCurrentLocaleDidChangeNotification object:nil];
[self reinitialize];
}
+ (NSInteger)numberOfMonths {
return shortMonthNames.count;
}
+ (NSArray *)shortMonthNames {
return shortMonthNames;
}
+ (NSArray *)longMonthNames {
return longMonthNames;
}
+ (NSInteger)firstWeekday {
return firstWeekday;
}
// Lots of other instance and class methods
As you can see, the initialize method sets up a notification handler so all of the static variables can be reinitialized if the locale is changed while the app is running.
Here is my Swift code. Since there is no initialize in Swift (any more), my solution is to use private backing variables for the public static variables.
import Foundation
public struct DateInfo {
// some normal instance properties irrelevant to the question
private static var _formatter: DateFormatter!
private static var formatter: DateFormatter {
if _formatter == nil {
_formatter = DateFormatter()
NotificationCenter.default.addObserver(forName: NSLocale.currentLocaleDidChangeNotification, object: nil, queue: nil) { (notification) in
_formatter = DateFormatter()
_shortMonthNames = nil
_longMonthNames = nil
_firstWeekday = nil
// reset all of the other statics as well
}
}
return _formatter
}
private static var _shortMonthNames: [String]!
public static var shortMonthNames: [String] {
if _shortMonthNames == nil {
// Processing is actually more complex than this simple assignment
_shortMonthNames = formatter.shortStandaloneMonthSymbols
}
return _shortMonthNames
}
private static var _longMonthNames: [String]!
public static var longMonthNames: [String] {
if _longMonthNames == nil {
// Processing is actually more complex than this simple assignment
_longMonthNames = formatter.standaloneMonthSymbols
}
return _longMonthNames
}
public static var numberOfMonths: Int {
return shortMonthNames.count
}
private static var _firstWeekday: Int!
public static var firstWeekday: Int {
if _firstWeekday == nil {
_firstWeekday = Calendar.current.firstWeekday - 1
}
return _firstWeekday
}
// lots of other similar private/public pairs of statics
}
Is this an appropriate way to translate the functionality given the need to be able to reinitialize the statics? I don't like having a private static backing each public static property.