Clicky

iOS Dev Nugget 116 method() is unavailable: use object construction Class()

.

Need to run a code review on your codebase? Hire me

This is the first Swift-related tip I am writing! Starting with this issue, I'll be covering both Swift and Objective C.

When you use Objective C code from Swift, you might notice an error like:

manager() is unavailable: use object construction SomeManager()

This happens if you have a class like this:

@interface SomeManager : NSObject
+ (instancetype)manager;
@end

+manager is likely meant to return a singleton and you were trying to call the equivalent of Objective C:

SomeManager* m = [SomeManager manager];

with:

var m = SomeManager.manager()

which triggers the error message. Using this as suggested by the error message will probably run, but it is wrong since it just creates an object by calling init():

var m = SomeManager()

This happens because of an interoperability feature of Swift for initialization which does some method name parsing based around naming conventions. Basically given an Objective C class like:

@interface SomeManager : NSObject
- (instancetype)initWithName:(NSString*)name;
- (instancetype)initWithName:(NSString*)name height:(int)aNumber;
@end

you can do the following in Objective C:

SomeManager* m1 = [[SomeManager alloc] initWithName:@"some name"];
SomeManager* m2 = [[SomeManager alloc] initWithName:@"another name" height:123];

Swift interoperability will let you do:

var m1 = SomeManager(name: "some name")
var m2 = SomeManager(name: "some name", height: 123)

You can see this with UIView's -initWithFrame: method.

In addition, Swift interoperability for initializers work for factory methods too, so given this Objective C class:

@interface SomeManager : NSObject
+ (instancetype)managerWithName:(NSString*)name;
+ (instancetype)managerWithName:(NSString*)name height:(int)aNumber;
@end

you can do the following in Objective C:

SomeManager* m1 = [SomeManager managerWithName:@"some name"];
SomeManager* m2 = [SomeManager managerWithName:@"another name" height:123];

Swift interoperability will let you do the following too:

var m1 = SomeManager(name: "some name")
var m2 = SomeManager(name: "some name", height: 123)

Unfortunately, if you have a class method that accepts no arguments like the +manager class method we talked about at the start of this tip, it can't be called directly from Swift. You'll need to create an Objective C class extension with a class method that wraps around it, that doesn't adhere to the naming convention. e.g.

@interface SomeManager (SwiftInterop)
+ (instancetype)singleton; //or some appropriate name
@end

@implementation SomeManager(SwiftInterop)
+ (instancetype)singleton {
    return [self manager];
}
@end

then you can call +singleton from Swift instead.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

.

.

Like this and want such iOS dev nuggets to be emailed to you, weekly?

Sign Me Up! or follow @iosdevnuggets on Twitter

.

View archives of past issues