I'm going through the book about Cocoa and Objective C ("Aaron Hillegass, Adam Preble - Cocoa Programming for Mac OS X - 2012") and when I did the example with NSTableView, I noticed that it really doesn't matter if I define my class as conforming to NSTableViewDataSource, NSTableViewDelegate protocols or omit them, only methods matter. (looks like sort of duck typing)
That is, the application works fine with both definitions:
#interface SpeakLineAppDelegate : NSObject <NSApplicationDelegate, NSSpeechSynthesizerDelegate, NSTableViewDataSource, NSTableViewDelegate>
and
#interface SpeakLineAppDelegate : NSObject <NSApplicationDelegate, NSSpeechSynthesizerDelegate>
It only yells at me at runtime if I don't implement 2 essential methods which are defined in NSTableViewDataSource, and in any case it doesn't matter at all if I put these protocols in class definition or not. So, what is the point in having them in the language? If they are only for documentation, we could put their names in comments as well, right? Or I'm missing something important here?
Protocol conformance can be checked at compile-time and runtime. Like most people said in the comments, protocol conformance is checked at compile-time. If you assign a type that doesn't conform to the protocol (other than id) to a variable of type bracketed with that protocol, the compiler should give you a warning. So in order to be able to pass an object that doesn't conform to a protocol to a parameter of that parameter type, you must have either 1) ignored a warning, or 2) gone through type id, which turns off static type checking.
The API you call also could (if it wanted to) check at runtime whether your objects formally conform to the protocol or not, using conformsToProtocol:. However, the convention in Cocoa is that the APIs never check for formal conformance to the protocol, but rather only check that it responds to a given selector when it needs to call it. This gives more flexibility to the user to, for example, use a class object (metaclasses can't formally conform to protocols, other than the ones conformed to by the root class) as a delegate.
Related
Trying to understand protocols and their use... having a hard time of it. The more I read, the less I am able to even formulate questions about them. I've read the statement "a protocol is a contract" a hundred times, but it just doesn't click.
I "only" want to develop really simple apps, so assume that I would not myself create a protocol for any of my classes.
I do want to use Apple's Scenekit framework, for example, and understand that I am required to implement some methods to do this - for example the SCNSceneRendererDelegate. The compiler enforces this, and it knows to do that because in my header file I have inserted:
#interface AAPLGameViewController : UIViewController <SCNSceneRendererDelegate>
the bit between the angle brackets specifically.
For the prototypes of the functions I have to implement, I go look for a
#protocol
...
#end
section in the SCNSceneRendererDelegate header file.
But now I've come across some #protocol sections (e.g. in the UIApplication header file) that contain #properties!! I thought #protocol was only about implementing certain methods, what is a property doing there?
I also came across in one of the answers here that specifying a protocol name when creating an instance of an object allows me to use objects that I know nothing about. I would be very grateful to get a few simple practical examples of where this would be useful.
And finally, in Java, the counterpart to (Obj-C) #protocols are called interfaces. Is there a counterpart in Java to (Obj-C) #interface?
Thanks much, cheers.
Adhering to a protocol tells other classes that your class has a specific set of characteristics. Usually protocols are used to define what methods a specific class should have so that it can be the delegate of another class, meaning the class adopting the protocol is guaranteed to have defined the required methods that the delegate class will call in a callback. If the protocol defines a property, it simply means any classes adopting the protocol are expected to also have that property. For example:
#protocol MyProtocol <NSObject>
#required
#property (readonly) NSString *title;
#optional
- (void) someMethod;
#end
I can now define a method anywhere that takes an object conforming to MyProtocol and safely access the title property because it is guaranteed to exist for all classes adopting MyProtocol.
-(void)printTitleOfObject:(id<MyProtocol>)object {
NSLog(#"%#", object.title);
}
So even though id can be any object, since we know that it conforms to our protocol we know that it has the title property. When people say "a protocol is a contract", what they mean is even if we don't know specifically what class is adopting the protocol, we know it at least has the methods and properties listed as required in the protocol. Specifying a protocol for a class allows us to know some information about it, even if we don't know what class it is.
Apple has written documentation for protocols they've written, like the SCNSceneRendererDelegate you mentioned in your question.
But now I've come across some #protocol sections (e.g. in the
UIApplication header file) that contain #properties!! I thought
#protocol was only about implementing certain methods, what is a
property doing there?
Properties are methods. A property declaration is simply a declaration for a getter-setter method pair (or if a readonly property, just a getter method), and allows the compiler to turn a dot notation access into a call to this getter and setter. That's all a property is. How the getter/setter is implemented (whether manually implemented or synthesized), and whether it reflects an underlying value or not (or is computed from other things) are private implementation details of the getter/setter methods.
The declaration of NSTextFieldDelegate really confuse me a lot.
In Xcode, I click "jump to defination" of NSTextFieldDelegate, and found:
#protocol NSTextFieldDelegate <NSControlTextEditingDelegate> #end
I have known that if we add a <...> syntax after a NSObject type (such as "id") declaration, that means this object comforms to the protocol specified in "<>".
However, books of Obj-C I have do not mentioned what it means when the "<>" means when it follows a protocol declaration...
So, Question 1: What does "<>" means when it is after a declaration of protocol?
I continued look into the NSControlTextEditingDelegate, and found several methods begin with "control:...". But what attracted me most was the text above the NSControlTextEditingDelegate defination:
#interface NSObject(NSControlSubclassNotifications)
- (void)controlTextDidBeginEditing:(NSNotification *)obj;
- (void)controlTextDidEndEditing:(NSNotification *)obj;
- (void)controlTextDidChange:(NSNotification *)obj;
#end
Oh, here comes new questions:
Question 2: What is the syntex "NSObject(NSControlSubclassNotifications)" means? What is NSControlSubclassNotifications actually?
Quesiont 3: What are the relationships among NSObject, NSControlSubclassNotifications and NSControlTextEditingDelegate? The apple doc simply says: "The NSTextFieldDelegate protocol adopts the NSControlTextEditingDelegate protocol and currently does not extend it further." But I could not understand its meaning...
It means that the protocol conforms to ("adopts") another protocol, so basically the protocol contains all the methods in both protocols. It's somewhat similar to subclassing.
It's a category, in this case used as an informal protocol. It fulfills pretty much the same purpose as a (formal) protocol here (though that's just one use case of categories), you'll mostly see this style in older APIs.
NSControlSubclassNotification is a category on NSObject. It basically adds new methods to all classes that inherit from NSObject. NSTextFieldDelegate is effectively the same as NSControlTextEditingDelegate, just with a different name, but it's possible that new methods might be added to it in the future that are unrelated to NSControlTextEditingDelegate, so that's probably why it's designed as a separate protocol.
I am trying to understand someone's code and ran into this.
There is a header file in which there is a protocol that specify a property of a UIButton.
In a separate implementation file (not the implementation for this header file), it was checking if a view controller "conformsToProtocol"
I understand if you have to conform to a protocol of methods, you have to implement those methods. But here,
What constitute conform and non-conform here?
It means that whatever conforms to that protocol must have the specified properties. (Remember, #properties are basically just shorthand for the underlying setter and getter methods, so you can also conform by having the appropriate setters and getters.)
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.
In Objective-C / Cocoa how do I discover the messages I can implement in a delegate class?
From what I have read in the documentation a class will only allow certain chosen messages to be handled via a delegate but so far have found difficulty finding a list of messages for a class.
To ask the question another way, if I created a delegate for NSApplication, which messages are available for me to handle?
The documentation for NSApplication states a delegate
responds to certain messages on behalf of NSApp.
The documentation then goes onto say
NSApplication defines over twenty delegate methods that offer opportunities for modifying specific aspects of application behavior.
but as far as I can see it fails to list these methods / messages so how do I know which ones will be called from my delegate?
The delegate is usually supposed to conform to a protocol declared for that purpose, e.g. NSApplicationDelegate. If it's not clearly spelled out already, you can often find the name of the appropriate protocol by looking at the type of the delegate property (in this case, id<NSApplicationDelegate>). You can check the documentation for details on the methods, or the #protocol declaration in the appropriate header file for specifics on which methods are available and which are required or optional.
There are some cases where the object does not define a protocol for its delegate, for example NSURLConnection. In this case, you just have to follow the documentation of the class with respect to what it expects of its delegate.
In either case, it is completely up to the class when it sends a message to the delegate and what the semantics of any message are.
These methods are described in the NSApplicationDelegate documentation:
http://developer.apple.com/library/mac/#documentation/cocoa/reference/NSApplicationDelegate_Protocol/Reference/Reference.html
One quick note that is that it is useful to understand the difference between formal and informal protocols. Also formal protocols have optional methods, which needn't be called.
When you write your own protocol you will want to check -respondsToSelector: before sending optional/informal methods.
formal protocols are defined like...
#protocol SomeProtocol <NSObject>
-(void)someMethod:(id)sender;
-(void)someOtherMethod:(NSString*)aString;
#property(nonatomic,retain) someProperty;
#optional
-(BOOL)someOptionalMethod;
#end
and are adopted like...
#interface SomeClass : NSObject <SomeProtocol> {
}
#end
this tells the compiler that you are adopting SomeProtocol, and you wont be required to declare you methods for the protocol in the .h file, it also tell the compiler to warn you if you haven't implemented all of the required methods.
for informal protocols you don't adopt them syntactically, but you will need to declare your methods in the .h file.