When to use respondsToSelector in swift? - objective-c

My question is more of a general question rather than a specific problem. It appears that for a class that is written in Swift, you can use the optional workflow to verify if the method does exist(?). If it doesn't, you can assume it returned nil.
This appears only to apply if the class is written in Swift. (Is that a correction assumption)?
Now, if you are referencing an Objective-C class and want to check to see if a method exists, you can use the respondsToSelector check with the selector #selector.
Is this meant to only be used on Objective-C classes and Swift classes, protocols, protocol /class extensions that inherit from Objective-C classes?
Let me know if I should expand on any part of my questions.

There is scarcely any need to call respondsToSelector explicitly in Swift. The only time when you'd want to do it is in dealing with an NSObject, and in that case, it is presumably an AnyObject or a delegate protocol adopter, and in either case you can just use question-mark syntax (which calls respondsToSelector for you).

It appears that for a class that is written in Swift, you can use the
optional workflow to verify if the method does exist(?). If it
doesn't, you can assume it returned nil.
This appears only to apply if the class is written in Swift. (Is that
a correction assumption)?
This is not correct. When you say "use the optional workflow to verify if the method does exist", I assume you mean what happens when you call methods on type AnyObject described in "Unrecognized Selectors and Optional Chaining" in the "id Compatibility" section in the Using Swift with Cocoa and Objective-C guide.
This feature only works with Objective-C (#objc) methods. AnyObject allow you to dynamically access only Objective-C (#objc) methods.
You can call any Objective-C method and access any property on an
AnyObject value without casting to a more specific class type. This
includes Objective-C compatible methods and properties marked with the
#objc attribute.
You cannot use AnyObject to call pure Swift (non-#objc) methods.

Related

objective-c override system method

I find a c++ system method causes crash in ios and I try to swizzle the method. However, I do not how to do that because it's a method of a c++ class. Anyone know whether can I do that?
Method swizzling is unique to objective-c (and even there one has to use it carefully), and is not applicable to c++.
I suppose that you don't have access to the source code of the c++ class.
Then the only way to "exchange" the implementation of a method at a specific c++-class is to derive a subclass, override the method, and then make sure that the subclass is used instead of the other class. It is still unlikely that you have a chance; the method being not virtual, the class to be replaced being used in non-polymorphic ways, the class to be replaced already having several subclasses, each of these points will prevent you from being successful.
Good luck though!

Swift isa pointer remapping or other supported method swizzling

Do Swift classes have something like an isa pointer that can be remapped?
We've seen that Swift uses a more static method dispatch than objective-C, which (unless a class dervices from Foundation/NSObject) prevents the style of swizzling based on remapping method implementations at runtime.
I'm wondering how we'll implement method interception-based dynamic features like the observer pattern, notifications, etc? Currently all this stuff is provided by the Objective-C layer, and can be easily integrated into Swift. But, if we want to provide these kinds of features in a framework (or app) of our own, is it necessary to implement them in Objective-C? I would assume there's a way to do it 'natively'.
Another kind of swizzling common to objective-C is remapping the isa-pointer to generate a sub-class on the fly. Is this kind of swizzling supported in Swift? If not what is the supported way of intercepting arbitrary method invocations?
Edit: As #jatoben points out, as of arm64 isa-remapping must be done by calling object_setClass() and not by accessing the value directly. This is still referred to as 'isa pointer swizzling'
It looks like both method exchanging and the isa pointer remapping technique only works if the Swift class has NSObject as a super-class (either directly or further up). It does not currently work, when the Swift class has no super-class or some other non-Foundation base class.
The following test shows this:
Class: Birdy
class Birdy: NSObject {
func sayHello()
{
print("tweet tweet")
}
}
Class: HodorBirdy
class HodorBirdy: Birdy {
override func sayHello()
{
super.sayHello()
print("hodor hodor")
}
}
Test:
func testExample() {
let birdy : Birdy = Birdy()
object_setClass(birdy, HodorBirdy.self)
birdy.sayHello();
}
And the output was as expected:
tweet tweet
hodor hodor
In this test both the base-class and sub-class were created in advance. Though they could also be created dynamically using the Objective-C runtime as long as the class has NSObject as an ancestor.
When a Swift class does not derive from the Objective-C foundation, then the compiler will favor static- or vtable-based dispatch, therefore its not clear how method interception will work at all in this case!
Unless the language/compiler make a specific allowance for it, we'll be foregoing dynamism in favor of performance. (Interception, which is the foundation of 'dynamic' behaviors can either be done at compile-time or run-time. In the case of static- or vtable-dispatch without a virtual machine, only compile-time applies).
I can't answer your question about swift "isa" equivalent, but I think I know part of the answer to your underlying question.
Property Observers seem to be the built-in means for the Observer Pattern. Instead of runtime discovery of "type" (RTTI, what-have-you) it is woven in explicitly.
From 'The Swift Programming Language' page 345:
Property observers observe and respond to changes in a property's
value. Property observers are called every time a property's value is
set, even if the new value is the same as the property's current
value.
You can add property observers to any stored properties you define,
apart from lazy stored properties. You can also add property observers
to any inherited property (whether stored or computed) by overriding
the property within a subclass.
You have the option to define either or both of these observers on a
property:
willSet is called just before the value is stored.
didSet is called immediately after the new value is stored.
I am not sure how this is all going to work out, but I am intrigued.
Relying on run-time type discovery also seems to run counter to strong static type orthodoxy.

Can an ObjC class object conform to a protocol?

Is there a way to indicate to the compiler that a class object conforms to a protocol?
As I understand, by creating +(void)foo class methods, an instance of that class object will have those methods as instance methods. So, as long as I create +(void)foo methods for all required protocol methods, I can have a class object act as a delegate.
My problem of course is that in the class's header file, I only know how to indicate that instances of the class conform to the protocol (as is typically the case). So, the best I've figured out is to cast the class object like so:
something.delegate = (id<SomethingDelegate>)[self class]
Any ideas?
Related, but different:
ObjC: is there such a thing as a "class protocol"?
What you're doing now is correct as it will silence warnings which is your goal. You will be sending the class object messages defined in the protocol for instances which is a bit confusing, but the runtime doesn't care.
Think about it this way: you want to set a delegate to an object that responds to the messages defined in the protocol. Your class does this, and your class is also an object. Therefore, you should treat your class like an object that conforms to that protocol. Therefore, what you've written is completely correct (based on what you're trying to do).
One thing to note, though, is this class will not properly respond to conformsToProtocol:. This is generally okay for a delegate setup anyway (delegates don't usually check if the class conforms — they just check if it can respond to a selector).
As a side note, one thing you can do syntactically is:
Class<SomethingDelegate> variable = (Class<SomethingDelegate>)[self class];
The difference here is that the compiler will use the class methods from the protocol instead of instance messages. This is not what you want in your case, though.
There is no Objective-C syntax to indicate that a metaclass conforms to a protocol.
I think you can do it at runtime, by using class_addProtocol on the metaclass. But I haven't tried it.
I guess you could also write a +conformsToProtocol: method on your class, and lie about your conformance. This could have unexpected side-effects, since there's already a +conformsToProtocol: on NSObject (in addition to -conformsToProtocol:).
Neither of these will eliminate the need for a cast to shut the compiler up. Just use a singleton.

Introspect parameter of type: id to decide whether it is a class or a protocol

I have the following method:
-(void)SomeMethod:(id)classOrProtocol;
It will be called like this:
[self someMethod:#protocol(SomeProtocol)];
Or
[self someMethod:[SomeClass class]];
Within the method body I need to decide if |classOrProtocol| is:
Any Class(Class) OR Any Protocol(Protocol) OR Anything else
[[classOrProtocol class] isKindOfClass: [Protocol class]]
Results in a (build)error:
Receiver 'Protocol' is a forward class and corresponding #interface may not exist
So how can I tell a Protocol from a Class from anything else?
In Objective-C 2 (i.e. unless you use 32 bit runtime on OS X) Protocol is defined to be just a forward class, see /usr/include/objc/runtime.h. The real interface is nowhere declared. You can try to include /usr/inlcude/objc/Protocol.h by saying
#import <objc/Protocol.h>
but as is written there, no method is publicly supported for an instance of Protocol. The only accepted way to deal with Protocol instances is to use runtime functions, given in Objective-C Runtime Reference. It's not even publicly defined whether Protocol is a subclass of anything, and it's not even stated that it implements NSObject protocol. So you can't call any method on it.
Of course you can use the source code of the runtime to see what's going on. Protocol inherits from Object (which is a remnant from pre-OpenStep NeXTSTep), not from NSObject. So you can't use the familiar methods for NSObject-derived objects, including Class of NSObject-derived objects. See the opensourced implementations of Protocol.h and Protocol.m. As you see there, the class Protocol itself doesn't do anything, because every method just casts self to protocol_t and calls a function. In fact, as can be seen from the function _read_images and others in objc-runtime-new.mm, the isa pointer of a Protocol object is set by hand when the executable and libraries are loaded, and never used.
So, don't try to inspect whether an id is a Protocol or not.
If you really need to do this, you can use
id foo=...;
if(foo->isa==class_getClass("Protocol")){
...
}
But, seriously, don't do it.
This is not an issue 'caused by inability to determine whether it's class or protocol. The error is 'caused by missing interface of Protocol class. Make sure you import Protocol.m at the top of your implementation file where you're testing argument's type.
You can also try using NSClassFromString() function which will return Class object or nil. Do note though that if nil is returned it doesn't mean that argument is protocol. It just means that it could be undefined class too!
There is also method NSProtocolFromString which returns appropriate results - Protocol for protocol and nil for undefined protocol.

Does the respondsToSelector method have to exist?

Does a method which I check for with respondsToSelector have to actually exist?
What if I only define it in the interface part and fail to implement it? I'm looking at a poor-man's virtual function in Objective-C.
First, yes the method actually has to exist for the check to succeed in the context you describe. respondsToSelector: will return NO if the method is not implemented.
More importantly, I think you mean a poor man's pure virtual function in Objective-C. All instance methods are "virtual" in Objective-C; since method lookup is done a run-time, the subclass' implementation will always be used, even from a pointer of the superclass type. In Objective-C, there is no such thing as a pure virtual base class. You can often achieve what you want by either using a #protocol to define an API or using a base class that provides an implementation that throws an NSNotImplementedException as its body. Subclasses would obviously have to override the implementation, making it effectively pure virtual.
Given that calling respondsToSelector: only makes sense when you don’t know whether a method exists, it’s not entirely clear what you mean.
If you mean, does some implementation of a method with the specified selector have to exist somewhere, the answer is no. Selectors merely represent names of methods. The #selector directive doesn’t reference any aspect of any method implementation.
respondsToSelector will return NO, since the selector isn't callable at run-time. The interface part only affects compilation.