In Swift programming language, it is mandatory that
“A designated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass initializer.” source of quote from another s/o
Otherwise, an error similar to the following would be displayed
Property 'self.baz' not initialized at super.init call
I would like to implement the following Objective-C code in Swift:
@interface FooBar : NSObject
@property (nonatomic, readonly) NSString *baz;
@end
@implementataion FooBar
@synthesize baz = _baz;
- (instancetype)initWithString:(NSString *)string {
self = [super init];
if (self) {
_baz = [self parseString:string];
}
return self;
}
- (NSString *)parseString:(NSString *)string {
// Perform something on the original string
return ...;
}
@end
The following implementation would have thrown a compiler error as described above:
class FooBar: NSObject {
let baz: NSString?
init(string: NSString?) {
super.init()
baz = parseString(string)
}
private func parseString(string: NSString?) -> NSString? {
// Perform something on the original string
return ...;
}
}
And if I did the following, I would get an error that says
Use of self in method call 'parseString' before super.init initialises self
class FooBar: NSObject {
let baz: NSString?
init(string: NSString?) {
baz = parseString(string)
super.init()
}
private func parseString(string: NSString?) -> NSString? {
// Perform something on the original string
return string;
}
}
So my solution, presently, is to use a private class method:
class FooBar: NSObject {
let baz: NSString?
init(string: NSString?) {
baz = FooBar.parseString(string)
super.init()
}
private class func parseString(string: NSString?) -> NSString? {
// Perform something on the original string
return ...;
}
}
My question is whether there is a better way to achieve the same or is private class method the best approach?
As you correctly mentioned the compiler complains about the "Use of self in method call 'parseString' before super.init initialises self". The reason for that is that the compiler has to ensure that you do not access anything on self
before it did finish initializing. Because the compiler does not want to (or even can not) check every outgoing method call before the initialization finished it simply disallows any usage of self before it finished.
Luckily your method parseString
does not want to change or access any property. Therefore you can and should make it a non-instance function. If it has nothing do with the instance of FooBar
, why should it have be only available on an instance of FooBar
?
You can simply make it a static
or class
function as you already did, which is perfectly fine.
But I would go even further and move it completely out of FooBar
. There are a few options for that:
Helper
where you define it as a class function
as wellHelper
where you define it as instance function
and create a Helper
instance in your class FooBar
or create a global one and pass that one in the init as well.