Swift error: class method "someMethod() is unavailable, use object construction Class()" - objective-c

Objective-C APIs do a lot of object construction using class methods:
+ (NSDate *)date;
+ (NSURL *)urlWithString:(NSString *)string;
+ (instancetype)layerWithSession:(AVCaptureSession *)session
Sometimes I even see these appearing in old Swift tutorials as class methods, but when I try to call them, I get compiler errors like these:
date() is unavailable, use object construction NSDate()
urlWithString() is unavailable, use object construction NSURL(string:)
layerWithSession() is unavailable, use object construction AVCaptureVideoPreviewLayer(session:)
(I see declarations like convenience init(URL url: NSURL) in the docs, and in Xcode's generated Swift interfaces for SDK classes, but what do they have to do with any of this?)
This even happens when I declare class methods in my own ObjC code, like for a singleton pattern:
#interface MyManager: NSObject
+ (instancetype)manager;
#end
When I try to use them from Swift, I get the same kind of errors:
let manager = MyManager.manager()
// error: 'manager()' is unavailable, use object construction 'MyManager()'
What gives? How do I fix these errors?

Swift does away with the alloc/init initialization pattern from Objective-C and replaces it with a construction syntax similar to that seen in Java or C++.
When, in a Swift class interface (or in Apple's documentation), you see something like:
class Thing {
init(number: Int)
}
That means you can create a Thing by calling it with the following "construction syntax":
let thingTwo = Thing(number: 2)
It doesn't matter if it's a class or a struct, or if you see other things like convenience or required or public before init... that's how you use it. (Of course, replace Thing with the type you're using, number with any parameter label(s) in the actual initializer you want, and 2 with an appropriate value for that parameter.)
When classes originally defined in ObjC are imported into Swift, the Swift compiler does a bunch of things to make those APIs look and feel more like native Swift code. One of those things is to replace the common pattern of using class methods as convenience constructors with real initializers.
All the examples from the question:
+ (NSDate *)date;
+ (NSURL *)urlWithString:(NSString *)string;
+ (instancetype)layerWithSession:(AVCaptureSession *)session;
... are such convenience constructors. That means they import into Swift not as class methods (NSDate.date(), NSURL.urlWithString(), etc), but as initializers:
class NSDate {
init()
}
class NSURL {
init?(string: String)
}
class AVCaptureVideoPreviewLayer {
init!(session: AVCaptureSession)
}
... and you call them with object construction syntax:
let date = NSDate()
let url = NSURL(string: "http://apple.com")
let layer = AVCaptureVideoPreviewLayer(session: mySession)
In fact, when you see error messages about "is unavailable, use object construction", Xcode pretty much always offers an automatic fix-it to insert the proper syntax.
How does this work? Swift looks for possible "base names" of a class and matches between those names and the class method / initializer method names. (It also checks for class methods that return an instance of that class, initializers that start with "init...", etc.)
For example, Swift sees the following as a convenience constructor:
#interface PDQMediaManager: NSObject
+ (PDQMediaManager *)manager;
#end
This may be a problem if what you (or the original developer of PDQMediaManager) intend is for that class to act as a singleton, and the +manager method to return the singleton instance — if a Swift developer writes PDQMediaManager(), they'll be constructing a new instance instead of retrieving the singleton.
In this case, one good solution is to rename the singleton method:
+ (PDQMediaManager *)defaultManager;
This won't get seen as a convenience constructor, so Swift clients can call PDQMediaManager.defaultManager() to get the singleton instance.
You can also use the NS_SWIFT_NAME to rename the singleton method only for Swift clients:
+ (PDQMediaManager *)manager NS_SWIFT_NAME(defaultManager());
If you don't control the codebase with the offending method, your best bet is probably to write your own ObjC code to forward to the singleton method and expose that to your Swift code via a bridging header.

Related

Swift native base class or NSObject

I tested out some isa swizzling with Swift, and found that it only works when NSObject is a super-class (directly or further up), or by using the '#objc' decoration. Otherwise it will follow a static- and vtable-dispatch style, like C++.
Is it normal to define a Swift class without a Cocoa/NSObject base class? If it is I'm concerned this means foregoing much of the dynamism of Objective-C, such as method interception and run-time introspection.
Dynamic run-time behavior sits at the heart of features like property observers, Core Data, Aspect Oriented Programming, Higher Order Messaging, analytical & logging frameworks and so on.
Using Objective-C's style of method invocation adds around 20 machine code operands to a method call, so in certain situations (many tight calls to methods with small bodies) C++ style static and vtable dispatch can perform better.
But given the general 95-5 rule (95% of performance gains come from tuning 5% of the code), doesn't it makes sense to start with the powerful dynamic features and harden where necessary?
Swift classes that are subclasses of NSObject:
are Objective-C classes themselves
use objc_msgSend() for calls to (most of) their methods
provide Objective-C runtime metadata for (most of) their method implementations
Swift classes that are not subclasses of NSObject:
are Objective-C classes, but implement only a handful of methods for NSObject compatibility
do not use objc_msgSend() for calls to their methods (by default)
do not provide Objective-C runtime metadata for their method implementations (by default)
Subclassing NSObject in Swift gets you Objective-C runtime flexibility but also Objective-C performance. Avoiding NSObject can improve performance if you don't need Objective-C's flexibility.
Edit:
With Xcode 6 beta 6, the dynamic attribute appears. This allows us to instruct Swift that a method should use dynamic dispatch, and will therefore support interception.
public dynamic func foobar() -> AnyObject {
}
I also found that if basing a Swift class on NSObject, I saw some unexpected run-time behaviour that could hide coding bugs. Here is an example.
In this example, where we don't base on NSObject, the compiler correctly spots the error in testIncorrect_CompilerShouldSpot,
reporting "... 'MyClass' is not convertible to 'MirrorDisposition'"
class MyClass {
let mString = "Test"
func getAsString() -> String {
return mString
}
func testIncorrect_CompilerShouldSpot() {
var myString = "Compare to me"
var myObject = MyClass()
if (myObject == myString) {
// Do something
}
}
func testCorrect_CorrectlyWritten() {
var myString = "Compare to me"
var myObject = MyClass()
if (myObject.getAsString() == myString) {
// Do something
}
}
}
In this example, where we base on NSObject, the compiler doesn't spot the error in testIncorrect_CompilerShouldSpot:
class myClass : NSObject {
let mString = "Test"
func getAsString() -> String {
return mString
}
func testIncorrect_CompilerShouldSpot() {
var myString = "Compare to me"
var myObject = MyClass()
if (myObject == myString) {
// Do something
}
}
func testCorrect_CorrectlyWritten() {
var myString = "Compare to me"
var myObject = MyClass()
if (myObject.getAsString() == myString) {
// Do something
}
}
}
I guess the moral is, only base on NSObject where you really have to!
According to the language reference, there is no requirement for classes to subclass any standard root class, so you can include or omit a superclass as needed.
Note that omitting a superclass from the class declaration, doesn't assign a implicit base superclass of any kind. It defines a base class, which will effectively become the root for an independent class hierarchy.
From the language reference:
Swift classes do not inherit from a universal base class. Classes you
define without specifying a superclass automatically become base
classes for you to build upon.
Trying to reference super from a class without a super class (i.e. a base class) will result in a compile time error
'super' members cannot be referenced in a root class
The following is copied from Apple's Swift-eBook and gives an appropriate answer to your question:
Defining a Base-Class
Any class that does not inherit from another class is known as a base class.
Swift classes do not inherit from a universal base class. Classes you define without specifying a superclass automatically become base classes for you to build upon.
Reference https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html#//apple_ref/doc/uid/TP40014097-CH17-XID_251
I believe that the vast majority of Swift data will not be objc. Only those parts that do need to communicate with te Objective C infrastructure will be explicitly marked as such.
To which extent runtime introspection will be added to the language, I do not know. Method interception will likely become only possible if the method explicitly allows it. This is my guess, but only the language designers within Apple really know where they are really heading.
It is normal. Look at the design goals of Swift: The goal is to make huge classes of programming problems disappear. Method swizzling is probably not one of the things that you want to do with Swift.

Fast enumeration on a class object

I'm implementing an application where both instances of a class as well as the class itself have "children" (placed inside a NSMutableArray). It's a pretty complicated application, but thanks to Objective-C, it's a breeze: classes are themselves objects and can have methods and "variables" (with the help of static variables and such).
To make it myself easy, I implemented accessor/setter method on both my instances (using -) and classes (using +) to fetch and manipulate the "children" without having direct access to the arrays. I like to have my objects as much as possible closed and the methods do some data validation.
I also implemented a fast enumeration instance method from the NSFastEnumeration protocol. And here comes the question: can I implement a fast enumeration class method and use it with Objective-C's for...in construct? In order words, can I implement this:
+ (NSUInteger)countByEnumeratingWithState: (NSFastEnumerationState *)state objects: (__unsafe_unretained id [])buffer count: (NSUInteger)len;
And then use it somewhere like that:
for (id child in [MyClass class]) {
// Do magic stuff…
}
I peeked in GNUStep's GSFastEnumeration.h file which implements fast enumeration as a macro, which affirms the above is possible, but I'm not sure if Apple does the same.
Even if I can't associate the NSFastEnumeration protocol to my class object, is fast enumeration without that protocol possible (and future-proof)?
The method -countByEnumeratingWithState:objects:count: is the whole of fast enumeration—the protocol is, I believe, mostly there for description (it's easier to implement a protocol than declare the method with the correct signature). I would expect it to work just fine, but I don't have a reference for that. You would probably want to loop over [MyClass class], though.
I would probably consider it future-proof. Note that it'd be really trivial to make a tiny wrapper class around your class object that does nothing but implement NSFastEnumeration and forward the instance method -countByEnumeratingWithState:objects:count: to your class's method +countByEnumeratingWithState:objects:count:.
I would recommend creating a protocol with a class method that is identical to the NSFastEnumeration method. You could then iterate over the [MyClass class] as John Calsbeek mentioned.
//Protocol implementation
#protocol FastClassEnumeration <NSObject>
#required
+ (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id [])buffer count:(NSUInteger)len;
#end
//Class implementation
#interface EnumeratedClass : NSObject<FastClassEnumeration>
#end
#implementation EnumeratedClass
+ (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id [])buffer count:(NSUInteger)len
{
static const unsigned long items_length = 4;
static NSString * items[items_length] = { #"item1", #"item2", #"item3", #"item4" };
if(state->state >= items_length)
{
return 0;
}
state->itemsPtr = items;
state->state = items_length;
state->mutationsPtr = (unsigned long *)self;
return items_length;
}
#end
//Usage
...
for(NSString *item in [EnumeratedClass class])
{
NSLog(#"%#", item);
}
...
can I ... ?
Well, did you try it? Does it work? If you've tried it, you would notice that it does indeed compile and work.
And why shouldn't it? Class objects are objects just like other objects. Class methods are just methods that happen to be on the class object. If you send a message to a class object, it will call a class method; whereas if you send a message to a non-class object, it will call an instance method. So pretty much, you can put class methods on a class and use the class object the same way you can use a normal object by putting instance methods on its class.
The only possible difference is that the class object won't explicitly conform to the NSFastEnumeration protocol, similar to if you loop over a normal object whose class does not explicitly specify that it conforms to the NSFastEnumeration protocol. So the question is, do they check that an object explicitly conforms to the protocol before using it (as opposed to checking if it responds to the selector)?
In my experience, for pretty much all of Cocoa, for APIs that say they require an object that conforms to a protocol, you can give an object that does not explicitly conform to the protocol, but implements all of the protocol's methods, and it will work fine. (How would they check it anyway? If they use conformsToProtocol:, that won't work for class objects since there's a +conformsToProtocol:, which has a different meaning. They would have to use runtime functions or special-case class objects probably.) For example, the NSDictionary documentation says its keys are required to conform to NSCopying, but if you have an object that does not conform to NSCopying, but does implement copyWithZone:, it works fine. (In fact, there is a +copyWithZone: method, whose stated purpose is to allow class objects to be used as dictionary keys, so obviously it is intended that keys don't need to explicitly conform to NSCopying.)

What's the difference between "class method" and "static method"?

I've worked with a few different languages such as Java, C#, and Objective-C.
In most languages, methods that don't require an instance of an object are called static methods. However, when it comes to Objective-C, some people get defensive when you call them static methods, and they expect you to call them class methods.
Why are they called class methods instead of static methods? What is the difference between a static method and a class method?
So my question is why are they called class methods instead of a
static method? What is the difference between a static method and a
class method?
From Wikipedia: Static methods neither require an instance of the class nor can they implicitly access the data (or this, self, Me, etc.) of such an instance.
This describes exactly what Objective-C's class methods are not.
An Objective-C class method very much requires an instance that is the target of the method invocation. That is, it requires an instance of the metaclass that describes the class object being invoked.
Unlike static methods, Objective-C's class methods can be inherited (which, in combination with having the aforementioned self, is exactly why many classes can share a single, simple, implementation of +alloc on NSObject without needing their own custom implementations) and invoking a class method goes through the exact same objc_msgSend* based dispatch mechanism as any other method call site.
Objective-C's class methods can be overridden across the class hierarchy and they can be swizzled. None of which is supported in languages that typically offer static methods in lieu of class methods.
The bottom line is that static methods and class methods are very different. While that difference is mostly transparent for day to day coding purposes, there are still situations where knowing how class methods work can save you a ton of unnecessary lines of code.
For example, you can't do this with static methods:
#interface AbstractClass:NSObject
+ factory;
#end
#implementation AbstractClass
+ factory
{
return [[[self alloc] init] autorelease];
}
#end
#interface Concrete1:AbstractClass
#end
#implementation Concrete1
#end
#interface Concrete2:AbstractClass
#end
#implementation Concrete2
#end
void foo() {
Concrete1 *c = [Concrete1 factory];
Concrete2 *d = [Concrete2 factory];
... etc ...
}
Because it's dynamically bound, not static.
Because it's really a class object's instance method.
Objective-C class method is actually an object's class object's instance method.
It's hard to describe with text. See nice illustration here.
http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html
Though class methods and static methods are in practice the same most of the time, they are different. With static methods the class is acting as a namespace qualifier. With class methods the class itself is an object and so class methods are to the class object exactly the same thing instance methods are to an instance; as a consequence you can do the following
#interface TestClass : NSObject
+ (void)classOrInstanceMethod;
- (void)classOrInstanceMethod;
#end
...
NSArray * arr = [NSArray arrayWithObjects:
[[[TestClass alloc] init] autorelease],
[TestClass class],
nil];
for( id obj in arr )
[obj classOrInstanceMethod];
which version of classOrInstanceMethod is called depends on whether obj is a class object or and instance. If you are familiar with the factory class pattern, this pattern is part of the Objective-C language.
This is purely a historical difference, mostly stemming from the fact that Objective-C was developed contemporaneously with C++, and before C++ or later languages like Java and C# had much influence. Objective-C was essentially a port of the Smalltalk object model to C, so its syntax and terminology don't necessarily seem as "C-like" as that used by C++. However, Objective-C was in no way bucking a trend by not using the term "static method", because that trend wasn't well-established back in 1983.

How do I provide a default implementation for an Objective-C protocol?

I'd like to specify an Objective-C protocol with an optional routine. When the routine is not implemented by a class conforming to the protocol I'd like to use a default implementation in its place. Is there a place in the protocol itself where I can define this default implementation? If not, what is the best practice to reduce copying and pasting this default implementation all over the place?
Objective-C protocols have no affordance for default implementations. They are purely collections of method declarations that can be implemented by other classes. The standard practice in Objective-C is to test an object at runtime to see if it responds to the given selector before calling that method on it, using -[NSObject respondsToSelector:]. If e object does not respond to the given selector, the method isn't called.
One way you could achieve the result you're looking for would be to define a method encapsulating the default behavior you're looking for in the calling class, and call that method if the object doesn't pass the test.
Another approach would be to make the method be required in the protocol, and provide default implementations in the superclasses of any classes wherein you may not want to provide a specific implementation.
There are probably other options as well, but generally speaking there isn't a particular standard practice in Objective-C, except perhaps to just not call the given method if it hasn't been implement by the object, per my first paragraph, above.
There is no standard way for doing that as protocols should not define any implementations.
Since Objective-C comes with a neat runtime, you can of course add such a behavior if you really think you need to do it that way (and there's no possibility by achieving the same with inheritance).
Say you declared MyProtocol, then just add an interface with the same name in the .h file under your protocol declaration:
#interface MyProtocol : NSObject <MyProtocol>
+ (void)addDefaultImplementationForClass:(Class)conformingClass;
#end
And create a corresponding implementation file (using MAObjCRuntime for readability here, but the standard runtime functions wouldn't be much more code):
#implementation MyProtocol
+ (void)addDefaultImplementationForClass:(Class)conformingClass {
RTProtocol *protocol = [RTProtocol protocolWithName:#"MyProtocol"];
// get all optional instance methods
NSArray *optionalMethods = [protocol methodsRequired:NO instance:YES];
for (RTMethod *method in optionalMethods) {
if (![conformingClass rt_methodForSelector:[method selector]]) {
RTMethod *myMethod = [self rt_methodForSelector:[method selector]];
// add the default implementation from this class
[conformingClass rt_addMethod:myMethod];
}
}
}
- (void)someOptionalProtocolMethod {
// default implementation
// will be added to any class that calls addDefault...: on itself
}
Then you just have to call
[MyProtocol addDefaultImplementationForClass:[self class]];
in the initializer of your class conforming to the protocol and all default methods will be added.
A truly fascinating way is to use the runtime. At the start-up, very early in the program execution, do the following:
Enumerate all the classes, find classes which implement the protocol
Check if the class implements a method
If not, add to the class the default implementation
It can be achieved without that much trouble.
I agree with "w.m." A very nice solution is to put all the default implementations into an interface (with the same name as the protocol). In the "+initialize" method of any subclass it can simply copy any unimplemented methods from the default interface into itself.
The following helper functions worked for me
#import <objc/runtime.h>
// Get the type string of a method, such as "v#:".
// Caller must allocate sufficent space. Result is null terminated.
void getMethodTypes(Method method, char*result, int maxResultLen)
{
method_getReturnType(method, result, maxResultLen - 1);
int na = method_getNumberOfArguments(method);
for (int i = 0; i < na; ++i)
{
unsigned long x = strlen(result);
method_getArgumentType(method, i, result + x, maxResultLen - 1 - x);
}
}
// This copies all the instance methods from one class to another
// that are not already defined in the destination class.
void copyMissingMethods(Class fromClass, Class toClass)
{
// This gets the INSTANCE methods only
unsigned int numMethods;
Method* methodList = class_copyMethodList(fromClass, &numMethods);
for (int i = 0; i < numMethods; ++i)
{
Method method = methodList[i];
SEL selector = method_getName(method);
char methodTypes[50];
getMethodTypes(method, methodTypes, sizeof methodTypes);
if (![toClass respondsToSelector:selector])
{
IMP methodImplementation = class_getMethodImplementation(fromClass, selector);
class_addMethod(toClass, selector, methodImplementation, methodTypes);
}
}
free(methodList);
}
Then you call it in your class initializer such as...
#interface Foobar : NSObject<MyProtocol>
#end
#implementation Foobar
+(void)initialize
{
// Copy methods from the default
copyMissingMethods([MyProtocol class], self);
}
#end
Xcode will give you warnings about Foobar missing methods, but you can ignore them.
This technique only copies methods, not ivars. If the methods are accessing data members that do not exist, you could get strange bugs. You must ensure that the data is compatible with the code. It is as if you did a reinterpret_cast from Foobar to MyProtocol.
As Ryan mention there are no default implementations for protocols, another option to implementing in the superclass would be is to implement a "Handler" kind of class that can be contained in any class that want to provide the default implementation, the appropriate method then calls the default handlers implementation.
I ended up creating a macro that has a default implementation of the method.
I've defined it in the protocol's header file, and then it's just a one-liner in each implementation.
This way, I do not have to change the implementation several places, and it's done on compile time, so no run-time magic is necessary.

Static constructor equivalent in Objective-C?

I'm new to Objective C and I haven't been able to find out if there is the equivalent of a static constructor in the language, that is a static method in a class that will automatically be called before the first instance of such class is instantiated. Or do I need to call the Initialization code myself?
Thanks
The +initialize method is called automatically the first time a class is used, before any class methods are used or instances are created. You should never call +initialize yourself.
I also wanted to pass along a tidbit I learned that can bite you down the road: +initialize is inherited by subclasses, and is also called for each subclasses that doesn't implement an +initialize of their own. This can be especially problematic if you naively implement singleton initialization in +initialize. The solution is to check the type of the class variable like so:
+ (void) initialize {
if (self == [MyParentClass class]) {
// Once-only initializion
}
// Initialization for this class and any subclasses
}
All classes that descend from NSObject have both +class and -class methods that return the Class object. Since there is only one Class object for each class, we do want to test equality with the == operator. You can use this to filter what should happen only once ever, versus once for each distinct class in a hierarchy (which may not yet exist) below a given class.
On a tangential topic, it's worth learning about the following related methods, if you haven't already:
- isMemberOfClass:(Class)aClass (true only for aClass itself)
- isKindOfClass:(Class)aClass (true for aClass and children)
+ isSubclassOfClass:(Class)aClass (same as above, but a class method)
Edit: Check out this post by #bbum that explains more about +initialize: https://web.archive.org/web/20201108095221/http://www.friday.com/bbum/2009/09/06/iniailize-can-be-executed-multiple-times-load-not-so-much/
Also, Mike Ash wrote a nice detailed Friday Q&A about the +initialize and +load methods:
https://www.mikeash.com/pyblog/friday-qa-2009-05-22-objective-c-class-loading-and-initialization.html
There is the +initialize class method that will be called before a class is used.
A bit of an addendum to this topic:
There is another way to create a 'static constructor' in obj-c, using an __attribute directive:
// prototype
void myStaticInitMethod(void);
__attribute__((constructor))
void myStaticInitMethod()
{
// code here will be called as soon as the binary is loaded into memory
// before any other code has a chance to call +initialize.
// useful for a situation where you have a struct that must be
// initialized before any calls are made to the class,
// as they would be used as parameters to the constructors.
// e.g.
myStructDef.myVariable1 = "some C string";
myStructDef.myFlag1 = TRUE;
// so when the user calls the code [MyClass createClassFromStruct:myStructDef],
// myStructDef is not junk values.
}