How do I know which functions need to be implemented by a class to conform to a protocol?
E.g. FBSDKAppInviteDialogDelegate requires appInviteDialog: didCompleteWithResults and appInviteDialog:didFailWithError:.
Xcode only gives an error without specifying these functions:
Type 'InviteFriendsController' does not conform to protocol
'FBSDKAppInviteDialogDelegate'
I found the functions in FBSDKAppInviteContent.h and they are surely mentioned in the FB docs. But is there an easier way to find the functions?
Yes, there is indeed an easier way to find the missing functions! You just need to click on the Arrow next to the error in the Issue Navigator and expand it:
If you hold command and press click the protocol name (in your case FBSDKAppInviteDialogDelegate), the navigator will bring you to the protocol declaration where you can see all the required methods and properties.
Related
In NotificationCenter Class , Why apple has created Observer of type Any?
func addObserver(Any, selector: Selector, name: NSNotification.Name?, object: Any?)
My Reasoning.
If observer is struct then on assigning inside as function parameter, It will be copied then how my observer can receive the notification.
I can't write any function which uses #objc prefix in Struct.
Selector is always be type of #objc.
So What is the use of Any in addObserver.....
It should always be of type AnyObject.
Secondly we already known that NotificationCenter keep the weak copy of observer, And we can't use weak modifier for type Any. Then how apple is managing all this?
Any help in understanding this concept is highly appreciated.
No one chose to make this parameter Any. It's just what they got by default. It's automatically bridged from ObjC:
- (void)addObserver:(id)observer
selector:(SEL)aSelector
name:(nullable NSNotificationName)aName
object:(nullable id)anObject;
The default way that id is bridged is Any. It hasn't been specially refined for Swift. In practice, you can't really use structs meaningfully here. The fact that the compiler won't stop you from calling it in an unhelpful way doesn't imply that it's intended to be used that way.
Why type Any? - because in Objective C it is type id.
Why you can't mark your function as #obj - #obc is the keyword for Swift code which indicates what compiler should add this method to a header file for this Class, yes you can make headers only for Classes.
Selector also is the objective-c term, it just says which function to invoke, similar to msg_send
In NotificationCenter Class , Why apple has created Observer of type Any.
Because all Objective-C id declarations are translated into Swift as Any.
You might object that this really should be AnyObject, because only a class will work here. And indeed, that's the way id used to be translated into Swift. But nowadays you can pass anything where an id is expected, because if it's something Objective-C can't understand, it will be boxed up as a class instance (e.g. as a _SwiftValue) so that it can make the round-trip into Objective-C and back again to Swift. Therefore id is translated as Any.
However, just because you can pass a struct here doesn't mean you should. It won't work, as you've discovered. Objective-C cannot introspect a Swift struct.
There are lots of situations like this, where Cocoa gives you enough room to hang yourself by passing the wrong thing. The contents of a CALayer is typed as Any, but if you pass anything other than a CGImage, nothing will happen. The layerClass if a UIView is typed as AnyClass, but you'd better pass a CALayer subclass. I could go on and on.
I am trying to write a registry in Swift that maps from API's (Protocols) to Implementations (Classes). I would like to be able to provide the registry an API and receive back an instance of the class that implements it. In Objective-C this was fairly trivial - just call NSStringFromProtocol on the protocol and then use that as a key for a dictionary containing the classes that implement them. In Swift, however, we do not have this introspective capability. When I try to do the same I am told that MyAPI.protocol does not have a member "mirrorType". My question to you is how, in Swift, without using #objc protocols, I can map from a protocol itself to the class that implements it. Thanks!
By now it's not possible without using #objc. The solution I've found in this case is using the protocol name (string) as a key for the dictionary for this implementations (In my case I'll always have only one instance per Protocol).
Using #objc will force you to have all your implementations returning AnyObject the equivalent (id) in objective-C (if your function does not return a native objective-C type).
Hope that helps.
I'm working with ReactiveCocoa in Swift. I need to use the following method:
rac_signalForSelector(selector: Selector, fromProtocol: Protocol?)
Passing the selector works fine with Selector("method:"), but I cannot find how to pass the delegate protocol to the fromProtocol parameter.
What is the proper way to pass the Protocol type from a delegate to a method signature like this?
EDIT: Adding method documentation and best attempt
The documentation for this method is as follows:
selector - The selector for whose invocations are to be observed. If it doesn’t exist, it will be implemented using information from protocol, and may accept non-object arguments and return a value. This cannot have C arrays or unions as arguments or return type.
protocol - The protocol in which selector is declared. This will be used for type information if the selector is not already implemented on the receiver. This must not be NULL, and selector must exist in this protocol.
I have tried sending in DelegateType.self, and I end up receiving this error:
Could not find an overload for rac_signalForSelector that accepts the supplied arguments
Did you use #objc when you declared your protocol?
I believe SomeProtocol.self is right right way to pass it but since you're passing it into an obj-c API it needs to be prefixed with #objc like this example from the docs:
#objc protocol HasArea {
var area: Double { get }
}
Edit: Turns out the protocol in question is from a library (written in objective-c, so already compatible with objective-c), not defined in Swift.
That being the case, it's probably a compiler bug, so before you do anything else make sure you're using the latest version of Xcode (beta 3 at the time of writing).
If that doesn't work out, I think Tommy's idea to use NSProtocolFromString is the best recourse until the compiler bug is fixed.
If I create a tableview in interface builder and connect the datasource and delegate to files owner there, do I also need to do this in the implementation of said viewcontroller?
#interface myViewController : UIViewController **<UITableViewDataSource**, **UITabBarControllerDelegate>**
ie manually specify protocol adherence?
Thanks,
When setting the delegate and datasource from interface builder there seems to be no reason to specify what protocols that class conforms to.
It works without manually specifying them because the language is pretty dynamic and this process of calling the delegate methods is done at runtime without being sure if the object does or doesn't have the required methods.
Only when setting the delegate/datasource from code there is some static type checking to see if the delegate/datasource conforms to the needed protocols.
Bottom line: write them. You get xcode autocompletion, maybe some warning in some cases, code documentation and some OCD fulfillment.
Yes. Specifying in the code that the class implements the protocols is what tells the XIB that you can make the connections and tells the compiler that all of the required methods from the protocols must be implemented (and a warning should be raised if they aren't).
Technically you can do without them, but you shouldn't.
Did you try it? Did it work without?
You're only able to connect them in interfacebuilder when you add the UITableViewDataSource and UITabBarControllerDelegate in your header file.
Just don't forget to implement the required methods (datasource & delegate) in you implementation. You'll get a warning when you do forget them btw.
I wasn't expecting my program to put up a fuss when I wrote this line of code:
[twitterFeed setDelegate:self];
twitterFeed is a UIWebView set to go to Twitter's mobile site, but that's beside the point. I'm getting the error "Sending 'SocialView (the name of the class that this is in) to parameter of incompatible type 'id'. I don't know how to fix it. Is there any way to do this quickly and without restructuring my code too much?
Also, it is worth noting that SocialView is a UIViewController, if that's at all important to you.
You could put <UIWebViewDelegate> in your SocialView interface declaration and see if that fixes the warning:
#interface SocialView : UIViewController <UIWebViewDelegate> {
...
}
If you are in a static method (with a +), you can manually get ride of the warning with a cast:
[twitterFeed setDelegate:(id<UIWebViewDelegate>)self];
If you are in an instance method (with a -), you should follow chown solution.
You probably want to read up on how delegates are used.
How does a delegate work in objective-C?
Make sure you know what you do when you use them.