I have a protocol like this:
#protocol ProfileSubObjects <NSObject, NSCoding>
#required
- (BOOL) hasGraph;
#optional
- (NSArray *) xGraphValues;
- (NSArray *) yGraphValues;
I want to make required this two optional methods if hasGraph is equal to YES.
Is it possible?
No. Methods are either required by a protocol or they're not. For one thing, the value of -hasGraph isn't known at compile time. Since it's an instance method rather than a class method, it's not even known at run time until you create a particular object. Furthermore, the object might report different values for -hasGraph at different times.
The best thing to do here is to simply document the fact that if -hasGraph returns YES, the -xGraphValues and -yGraphValues are expected to be implemented. You could enforce that by throwing an exception, or you could fail gracefully and just not draw any data if those methods aren't implemented. Use the -respondsToSelector: method to check whether the method is implemented before you call it.
No, it's not possible. At least, not like this. However there is a deeper issue. The question suggests consideration of compile versus runtime checking and object orientation.
Marking something as #optional or #required means that you wish to perform compile time checking that those objects fulfil the protocol contract of providing implementations - or not in the case of #optional - of those methods.
Therefore there is no reason to have that compile time checking dependent upon the value of a runtime variable, in this case hasGraph.
A better approach would be to make use of the respondsToSelector message check. Alternatively you could have a subclass that has a graph and supplies x and y graph values.
That's not possible; the result of hasGraph will be known only at runtime, whereas the required/optional parts of a protocol are used for the compiler to check things out at compile time.
What you probably want to do is to add a strong note to the effect that if hasGraph returns YES then xGraphValues and yGraphValues must be implemented, bringing a little informality to your formal protocol. You can always do something like:
if([object respondsToSelector:#selector(xGraphValues)] &&
[object respondsToSelector:#selector(yGraphValues)])
To verify at runtime whether an object implements the parts of the protocol you need in order to be able to do a particular operation on it. It'd probably be smart to put that stuff in an NSAssert if you want someone who implements a non-conformant object to be able to find out what they did wrong through a debug build.
Related
Is it more appropriate to check a class's type by calling isKindOfClass:, or take the "duck typing" approach by just checking whether it supports the method you're looking for via respondsToSelector: ?
Here's the code I'm thinking of, written both ways:
for (id widget in self.widgets)
{
[self tryToRefresh:widget];
// Does this widget have sources? Refresh them, too.
if ([widget isKindOfClass:[WidgetWithSources class]])
{
for (Source* source in [widget sources])
{
[self tryToRefresh:source];
}
}
}
Alternatively:
for (id widget in self.widgets)
{
[self tryToRefresh:widget];
// Does this widget have sources? Refresh them, too.
if ([widget respondsToSelector:(#selector(sources))])
{
for (Source* source in [widget sources])
{
[self tryToRefresh:source];
}
}
}
It depends on the situation!
My rule of thumb would be, is this just for me, or am I passing it along to someone else?
In your example, respondsToSelector: is fine, since all you need to know is whether you can send the object that message, so you can do something with the result. The class isn't really that important.
On the other hand, if you were going to pass that object to some other piece of code, you don't necessarily know what messages it will be intending to send. In those cases, you would probably be casting the object in order to pass it along, which is probably a clue that you should check to see if it really isKindOfClass: before you cast it.
Another thing to consider is ambiguity; respondsToSelector: tells you an object will respond to a message, but it could generate a false positive if the object returns a different type than you expect. For example, an object that declares a method:
- (int)sources;
Would pass the respondsToSelector: test but then generate an exception when you try to use its return value in a for-in loop.
How likely is that to happen? It depends on your code, how large your project is, how many people are writing code against your API, etc.
It's slightly more idiomatic Objective C to use respondsToSelector:. Objective C is highly dynamic, so your design time assumptions about class structure may not necessarily hold water at run time. respondsToSelector: gets round that by giving you a shortcut to the most common reason for querying the type of a class - whether it performs some operation.
In general where there's ambiguity around a couple of equally appealing choices, go for readability. In this case that means thinking about intent. Do you care if it's specifically a WidgetWithSources, or do you really just care that it has a sources selector? If it's the latter, then use respondsToSelector:. If the former, and it may well be in some cases, then use isKindOfClass. Readability, in this case, means that you're not asking the reader to make the connection between type equivalence of WidgetWithSources and the need to call sources. respondsToSelector: makes that connection for the reader, letting them know what you actually intended. It's a small act of kindness towards your fellow programmer.
Edit: #benzado's answer is nicely congruent.
Good answers from #Tim & #benzado, here is a variation on the theme, the previously covered two cases first:
If at some point you have may have a reference to distinct classes and need them differently then this is probably a case for isKindOfClass: For example, an color might be stored in preferences as either an NSData serialization on an NSColor, or as an NSString value with one of the standard names; to obtain the NSColor value in this case isKindOfClass: on the object return is probably appropriate.
If you have a reference to a single class but different versions of it over time have supported different methods then consider respondsToSelector: For example, many framework classes add new methods in later versions of the OS and Apple's standard recommendation is to check for these methods using respondsToSelector: (and not an OS version check).
If you have a reference to distinct classes and you are testing if they adhere to some informal protocol then:
If this is code you control you can switch to a formal protocol and then use conformsToProtocol: as your test. This has the advantage of testing for type and not just name; otherwise
If this is code you do not control then use respondsToSelector:, but we aware that this is only testing that a method with the same name exists, not that it takes the same types of arguments.
Checking either might be a warning that you are about to make a hackish solution. The widget already knows his class and his selectors.
So a third option might be to consider refactoring. Moving this logic to a [widget tryToRefresh] may be cleaner and allow future widgets to implement additional behind the scenes logic.
Assume that:
New Protocol is declared
Method in this protocol is marked #required
Class conforms to Protocol
Class does not implement the method mentioned in Protocol
At compile time, information about this method is known: i.e. that it is required and that this class and any other classes this class may may extend do not implement it.
Why in this case the compiler issues a warning and not an error?
Errors are only issued when the compiler cannot continue because something went terribly wrong.
When calling a method in Objective-C, the method lookup is done during runtime and not during compilation, which C++ does. In Objective-C a "message" is simply sent to the object, something like obj.executeCommand("Hey, can you execute function <name> for me?"). In C++ the object will be called directly, in a way like obj.<name>(). In the case of Objective-C the executeCommand() method is called, which exists. In C++'s case the function is called but it does not exist. These are methods that are linked on the compiler level, which means they both become memory addresses rather than names. executeCommand becomes 0x12345678 but it still uses the same message ("execute function <name>").
This is probably very confusing, but it's related to the way methods are implemented in different languages.
If you feel strongly about it, why not turn on -Werror?
I don't know the real answer but here is a use case that would go against it.
What if you implemented all of the protocol methods in a category???
Main interface declaration adopts the protocol however the protocol method implementation is in a category.
This is valid code but will show compile error if compiler was that strict !!
Objective-C is a dynamic language. The idea of what an implementation is, is different to a static language.
For the most part, it's in code that most of us implement inside the #implementation ... #end block.
But what if a method is not found? Then an object has a chance deal with it dynamically.
Imagine you have an interface for a sound effect player:
#protocol FX
- (void)playBeep;
- (void)playSiren;
- (void)playHonk;
#end
An implementation could have the files Beep.mp3, Siren.mp3, Honk.mp3 to play, but instead of implementing each of the methods, it could override -forwardInvocation: and parse the selector string, something like this pseudocode:
NSString *selName = NSStringFromSelector([invocation selector]);
if ([selName startsWith:#"play"]) {
NSString filename = fileNameFromSelector(selName);
[self playSoundFileNamed:filename];
}
This may seem contrived, but once you start using the dynamic features of the language, you will start finding more and more places where it makes sense. And by sense I mean, does this effort help in the long run?
In the above case, just add a -sound* method name to the interface, and drop in a appropriately named sound file. It just works.
Another example from personal experiments: how to deal with Core Data entities in a more natural way. I want to do this:
NSArray *people = [Person findAllWithNameLike:#"B%"];
instead of mucking about with predicates, fetch requests etc.
But I don't want to define every permutation of method in code.
How about if I wanted to build an XML builder? I would look at a dynamic approach. It has served Groovy Builders well (look at Groovy/Grails for examples).
One last example: I have a traits system where I can define behaviours in the form of groups of methods and have my objects assimilate this behaviour. So, while the compiler doesn't see an implementation for the interface my object conforms to, the implementation is injected into it from a trait class, using the Objective-C runtime. Why would I do this? I find many delegate methods are boiler plate, but at the same time, a single base class for each situation is not flexible enough. Instead of cut and paste from code samples, my 'samples' compile and run :) and any changes are reflected across all projects using the trait.
To really understand why all this is available to you, it is worth playing around with a Smalltalk environment (search Pharo or Squeak). This is where Objective-C has its roots.
And finally, to stop these warnings:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wprotocol"
#implementation ... #end
#pragma clang diagnostic pop
Because there are times when there are bogus "required" methods in a poorly designed protocol.
They should have been optional but someone insisted they are "required".
Thusly making this a run time issue rather than a compile bug is very very wise.
I've been writing various stuff using protocols as per example code, but also using some third party stuff, and they seem to adopt quite different approaches. Some specifically adopt the protocols in the interface using
#interface myClass <myProtocol>
others don't do that at all and merely pass themselves and are then set as delegates, but the end result seems to be exactly the same. I've tried both, and they both work fine. If someone was able to explain this I'd be a happy camper! Thanks very much.
A protocol declares a set of messages that an object must respond to (or with #optional, can respond to). In Objective-C, its only point (almost)* is to allow the compiler to flag up warnings if you pass an object that doesn't implement all the methods of the protocol with the correct signatures.
Taking a simple example: NSMutalbeDictionary has a method -setObject:ForKey: which sets the value for a particular key. The key is declared as type id which means you can pass any object and the compiler will not complain. However, the documentation for the method says:
The key is copied (using copyWithZone:; keys must conform to the NSCopying protocol).
so if you pass an object that doesn't have a -copyWithZone: method, you will get a exception at run time saying the key does not respond to -copyWithZone:. It would have been nice if the compiler could have detected your error.
If Apple had declared the method
-(void)setObject:(id)anObject forKey:(id<NSCopying>)aKey;
the compiler would have known about the requirement for -copyWithZone: (it's the only method declared in NSCopying) and would have caught any instances of passing incompatible objects at compile time. I think the reason they didn't do that is for backward compatibility. If bbum is reading, he might know the real reason why not.
*I say "almost" because you can test to see if an object conforms to a protocol at run time.
Objective-C can do both static and dynamic typing, so that protocols aren’t really required for the usual use cases. You can always type your delegate as id and then send it whatever messages you want. (The compiler will warn you if you attempt to send a message that’s not visible from the current file. That’s about the only sanity check it can do for id-typed objects without doing advanced type inference.)
But narrowing the id type down with protocols is nice and recommended, because 1) the code is more readable, 2) the compiler will warn you if you try to send the delegate some bogus message and 3) you’ll get better code completion.
Also the Xcode Code Sense can be very helpful if you use protocols. Sometimes it will suggest the missing methods.
What is better and why ?
What is better in such situations as the class init method and usual variables in a code ?
What is better and why ?
Explicit typing information is always better unless you just can't use it for some reason (see below).
It allows the compiler to much more stringently validate the code and will catch many errors at compile time that would otherwise cause your app to crash at runtime.
A long, long, time ago, everything in the APIs used id. This proved to be a complete pain in the butt; fragile and led to many crashes that would have been caught with specific types.
So, it was changed. (This was ~1994).
What is better in such situations as
the class init method and usual
variables in a code ?
For init, you have no choice but to use the generic (id) return type. Objective-C does not support either co-variant or contra-variant declarations, nor is there a mechanism for generalizing the declaration of init while also providing support for specific type checking.
Same goes for retain, objectAtIndex:, addObject: and many other methods that take or return one of many kinds of objects (or take 'em as arguments).
And, no, there is absolutely no performance difference whatsoever between id and, say, NSView*.
can you give an example when explicit
typing will cause a problem please?
If you wrote:
- (MyClass *) init;
And in a subclass:
- (MySubclass *) init;
You'd get compiler warnings out the wazoo most likely or you'd have to typecast out the wazoo.
On recent versions of clang (in Lion) you should actually not return id, and instead return instancetype. This is a keyword that is used in return types to specify that the type it returns is an instance of the class receiving the message. It is now the preferred return type for init methods on OS X Lion.
Explicit typing provides build-time protection, informing you of likely problems if you do things such as casting or performing operations on something that probably won't work.
Explicit typing also helps prevent non-obvious transfer of mistyped objects, something traveling through a path in your code you hadn't considered that turns out to be of an unexpected type. This kind of bug often doesn't become clear until the program has been tested a lot, more commonly after its release.
It's also helpful for future programmers (including your future self) trying to work with your code, making to more likely that they'll be able to tell at glance what an object is supposed to be. It makes code more "self-documenting" as a result.
Some things cannot have a meaningful type because no type actually applies. Other times you need to use id because you need to be able to accept any type of object. Cocoa Touch uses it, for example, when referring to the sender of a message because anything could have sent it; specifying an explicit type simply wouldn't work.
The vast majority of the time, though, an explicit type is to your advantage.
Use a type as specific as you can but not more so. Consider how you are using any particular variable, argument, or return type and set its type appropriately.
For example a UITableView's dataSource property is declared as id<UITableViewDataSource> because the table view only cares that its data source is some object which conforms to the UITableViewDataSource protocol. This allows the data source to be flexible enough for use with any specific class which implements the protocol but still allows the compiler to warn you if you attempt to assign an object which does not implement that protocol as the data source.
If you are too specific then your code becomes inflexible, accepting only specific implementations which are not strictly necessary (ie demanding a NSMutableString when you could really work with any NSString).
If you are too vague (typing everything as id for example) then you lose the ability to identify when you are sending unrecognized selectors to a particular instance and the compiler cannot identify any number of invalid statements.
For init methods follow the advice in The Objective-C Programming Language
The return type of an initializer method should be id.
The reason for this is that id gives an indication that the class is purposefully not considered—that the class is unspecified and subject to change, depending on context of invocation. For example, NSString provides a method initWithFormat:. When sent to an instance of NSMutableString (a subclass of NSString), however, the message returns an instance of NSMutableString, not NSString. (See also, though, the singleton example given in “Combining Allocation and Initialization.”)
I don't think there is a performance difference between both.
You can let id return type for init because you can cast the result of your init.
For exemple :
Toto *foo = [[Toto alloc] init];
id foo2 = [[Toto alloc] init];
Both work but you'll have to cast foo2 variable like that (Toto *)foo in order to access property or methods of your instance without creating a compiler warning. Even if it works fine...
I think some developers let id because they just pass there variable trough instance and don't use it. That kind of use allow to not import the .h
Regards,
KL94
This is not an actual Xcode error message, it is a warning that has been haunting me for
a long time. I have found no way of removing it and I think I maybe have overstepped some unwritten naming convention rule.
If I build a class, most often extending NSObject, whose only purpose is to do some task and report back when it has data, I often give it a convenience constructor like "initWithDelegate".
The first time I did this in my current project was for a class called ISWebservice which has a protocol like this:
#protocol ISWebserviceDelegate
#optional
- (void) serviceFailed:(NSError*) error;
- (void) serviceSuccess:(NSArray*) data;
#required
#end
Declared in my ISWebservice.h interface, right below my import statements.
I have other classes that uses a convenience constructor named "initWithDelegate".
E.g. "InternetConnectionLost.h", this class does not however have its methods as optional, there are no #optional #required tags in the declaration, i.e. they are all required.
Now my warning pops up every time I instantiate one of these Classes with convenience constructors written later than the ISWebservice, so when utilizing the "InternetConnectionLost" class, even though the entire Class owning the "InternetConnectionLost" object has nothing to do with the "ISWebservice" Class, no imports, methods being called, no nothing, the warning goes: 'ClassOwningInternetConnectionLost' does not implement the 'ISWebserviceDelegate' protocol
I does not break anything, crash at runtime or do me any harm, but it has begun to bug me as I near release. Also, because several classes use the "initWithDelegate" constructor naming, I have 18 of these warnings in my build results and I am getting uncertain if I did something wrong, being fairly new at this language.
Hope someone can shed a little light on this warning, thank you:)
The cause here is that you have multiple interfaces in your project that have functions defined as initWithDelegate:(id).
Alloc only returns id, so the compiler doesn't know the type, it therefore doesn't know which initWithDelegate is being used and seemingly uses the first one in the list. Thus you get a warning that makes no sense.
The runtime knows the type of the object however, and thus doesn't have any trouble.
The solution seemingly is to use more verbose init methods, eg. initWithWebServiceDelegate. Or to cast after the alloc:
[(Foo *)[Foo alloc] initWithDelegate:self]
Your getting the warning because the compiler thinks that the classes have declared that they implement the ISWebserviceDelegate protocol. I doubt it has anything to do with the intiWithDelegate method unless your inheriting the method or you've defined the method in a protocol that itself is an extension of ISWebserviceDelegate protocol.
The usual cause of this is declaring the adoption of the protocol in a superclass and then forgetting to implement in that superclass of a subsequent subclass.
If you're sure that is not the case, then you probably just need to clean the project and rebuild. You most likely did declare at one point, then undeclared but the compiler is stuck on the old declaration.
If the clean does not resolve, I would do a project find on ISWebserviceDelegate and make sure its not tucked away somewhere.