Why do I have to cast the delegate? - objective-c

I have a class and this class has a delegate protocol. I create an object in the main class using this class and assigned the main class as the delegate. The main class has a property I would like to read inside the created class. Then I do this:
BOOL prop = [self.delegate myProperty];
Xcode complains that "delegate may not respond to myProperty"
If I am sending a message to self.delegate to read myProperty, and generally Xcode never complains when you send a message to an not casted object, why do I have to do that
BOOL prop = [(myMainClass *)self.delegate myProperty];
to make it work?
To be more clear, here is an example of a message sent to an object without having to cast:
[self.myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop){
int Number = [[obj dictionaryOfNames] count];
}];
self.myArray is an array of objects from another class that are dictionaries and have this property dictionaryOfNames. Xcode never asked me to cast this:
int Number = [[(myOtherClass *)obj dictionaryOfNames] count];
as I had to above for myProperty.

Different classes can conform to a protocol. If you declare that you conform to a protocol you just say that you will implement the requiered methods but you can implement it in a UIView, UIViewController, MyOwnClass, MyOtherClass etc.
Thats why a property is normally declared like this
#property (nonatomic, weak) id <MyProtocol> delegate;
So you just say your delegate is an object which conform to the protocol.

You haven't shown enough code to give a completely definitive answer, but in general terms I would expect that the definition of your delegate is not just id, you've probably used NSObject* or something similar.
The compiler is doing "static" analysis of your source code and trying to determine whether or not the object specified by "self.delegate" might implement that method. If the data type is, say, NSObject*, then the compiler looks through that specific class definition to see if your method is present; if it isn't, then you'll get a warning.
If the data type of the message receiver is id, the compiler tends to give up and say "well, it could be anything so I'll assume this will work".
The result of the expression [obj dictionaryOfNames] is probably of type NSDictionary and the compiler can see that that particular class does respond to the count method.
Note, you can also get this problem if you have specified a class name for a property, but the compiler cannot see the entire class definition from this file. For example, if you have
myobject.h:
#class Something;
#interface MyObject
#property (retain) Something *delegate;
#end
myobject.m:
#import "myobject.h"
[self.delegate doItYouFool];
then the compiler can see that the result of the expression 'self.delegate' is of type Something* but it can not see the actual definition of that class and thus can't look through its supported messages. This usually results in a warning about 'forward definitions'. To fix it, you should import "something.h" into the .m file, so that the compiler has full knowledge about the classes it is working with. To just silence the warning, you cast to id
[(id)self.delegate doItYouFool];
You may, of course, also be getting warnings that 'doItYouFool' isn't a known method, again because you haven't included the header file that defines that message.

Related

Why does adding a protocol (to id) cause semantic issues?

Let's say I have a trivial class like this:
#interface ABPair : NSObject
#property id key;
#property id value;
- (void) printSize;
#end
#implementation ABPair
- (void) printSize {
NSLog(#"the size of your key is: %#", NSStringFromSize([self.key sizeWithAttributes: nil]));
}
#end
This compiles with no warnings (in Xcode 5), and runs successfully, and prints a reasonable value.
However, if I made this one change:
#property id<NSCopying> key;
then I get two compiler errors:
ARC Semantic Issue: No known instance method for selector 'sizeWithAttributes:'
Semantic Issue: Passing 'id' to parameter of incompatible type 'NSSize' (aka 'struct CGSize')
Why is the compiler able to identify the proper method (on NSString) when I provide no information at all about the type, but unable to identify the method when I say that the object must be of a protocol to which that class conforms?
id key declares a "generic" Objective-C variable. It can point to any object,
and the compiler accepts any messages sent to it.
If you compile with ARC, it is only required that the message signature is known
to the compiler at all (from any class).
id<myprotocol> key specifically declares a pointer to an object conforming to that protocol.
The compiler accepts only messages from the <myprotocol> protocol (or other protocols that <myprotocol> inherits from).

Deduction of instancetype by LLVM compiler

I have this piece of code:
#interface Bar : UIView
- (id)initWithInt:(int)i;
#end
#implementation Bar
- (id)initWithInt:(int)i {
self = [super init];
return self;
}
#end
void func() {
[[[Bar alloc] initWithInt:10] doSomething];
}
The compiler gives me an error in the func() function: No visible #Interface for Bar declares the selector doSomething.
I do have another #interface with the method doSomething.
The compiler somehow assumed that initWithInt: returns instancetype rather than id.
What are the rules to this? In what cases does a compiler assume that a method returns instancetype?
In what cases does a compiler assume that a method returns
instancetype?
That is documented in "CLANG LANGUAGE EXTENSIONS":
According to Cocoa conventions, Objective-C methods with certain names
(“init”, “alloc”, etc.) always return objects that are an instance of
the receiving class’s type. Such methods are said to have a “related
result type”, meaning that a message send to one of these methods will
have the same static type as an instance of the receiver class.
...
To determine whether a method has an inferred related result type, the first word in the
camel-case selector (e.g., “init” in “initWithObjects”) is considered,
and the method will have a related result type if its return type is
compatible with the type of its class and if:
the first word is “alloc” or “new”, and the method is a class method,
or the first word is “autorelease”, “init”, “retain”, or “self”, and
the method is an instance method.
So your initWithInt: method has a "inferred related result type", and
therefore the compiler assumes that it returns an instance of Bar.
don't know BUT
inits always should return instance types anyways. it is only logical. I cannot imagine any other situation.
Just import the subclass that declares doSomething and you're good
I do have another #interface with the method doSomething.
Each class must have exactly one #interface (although you can make class extension, categories, etc. to add further methods). If your -doSomething method is in a category (or class extension) in another file, make sure that its declaration is visible in this file via an #import.

Exposing/Synthesizing iVar properties in Objective c

I have a class that essentially acts as a light weight wrapper class around another class. It holds that other class as an iVar. I want to be able to expose certain properties (quite a few actually) of the iVar, but to do so I have to write out each property accessor like so:
- (void) setProperty:(Class *)value{
_iVar.property = value;
}
- (Class *) property{
return _iVar.property;
}
Of course, I have to do this for every single property, which is a pain (there are about 30 of them). I would love to be able to synthesize this but I haven't been able to figure out how.
Is it possible to synthesize?
Also, I can't subclass....well, I might be able to but it's really not recommended. The iVar class is really quite heavy (it implements CoreText). I'd rather write out the methods by hand.
Ok, so here's the solution I found...ended up being pretty simple once you knew what to do. First overwrite '- (id) forwardingTargetForSelector:(SEL)aSelector' and return the iVar:
- (id) forwardingTargetForSelector:(SEL)aSelector{
return iVar;
}
When the runtime is looking for a method and cannot find one, it will call this method to see if there is another object to forward the message to. Note that this method normally returns nil and if you return nil here, your program will crash (which is the appropriate behavior).
The second part of the problem is to shush the compiler errors/warnings you'll get when you try to send a message that's not declared. This is easily done by declaring a category you don't implement.
#interface Class (iVarClassMethods)
#propoperty (strong) Class *property1;
......more properties
#end
As long as you don't put in an implementation anywhere, aka #implementation Class (category), the compiler won't complain (it'll assume that the implementation is somewhere....).
Now the only drawback I see is if you change any of the properties in the interface of the iVar Class, you need to make sure you update all other classes that use the method described above, otherwise you'll crash when another class tries to send what is now the wrong method (and the compiler won't warn you beforehand). However, this can be gotten around. You can declare protocols in a category. So instead you create a separate protocol for the iVar class and move the methods/properties you wish out of the iVar class into the protocol.
#protocol iVarClassProtocol
#propoperty (strong) Class *property1;
......more properties
#end
Add that protocol to the iVar subclass so it has those methods declared through the protocol now.
#interface iVarClass <iVarClassProtocol>
....other methods/properties you don't need forwarded
#end
Finally, simply add the protocol to the category. So instead of the aforementioned category with explicit declarations you'll have:
#interface Class (iVarClassMethods) <iVarClassProtocol>
#end
Now, if you need to change any of the to-be-fowarded properties/methods, you change them in the protocol. The compiler will then warn you when you try to send the wrong method to the forwarding class.
I think you can forward the messages to the ivar:
- (void) forwardInvocation: (NSInvocation*) invocation
{
[invocation invokeWithTarget:ivar];
}
- (NSMethodSignature*) methodSignatureForSelector: (SEL) selector
{
NSMethodSignature *our = [super methodSignatureForSelector:selector];
NSMethodSignature *ivars = [ivar methodSignatureForSelector:selector];
return our ? our : ivars;
}
Then you have to hide or fake the type of your object, for example by casting to id, otherwise the compiler will complain that your class does not implement those methods.
Of course it would be best if you could come up with some better design that would do without such tricks.

type casting self

What does the following casting of self do "ClassA*"? Does this type caste allow you to access ClassA?
ClassA.h:
#interface ClassA: NSObject {
NSUInteger _someNumber;
ClassB *_classB;
}
#property (nonatomic,retain) ClassB *classB;
#property (nonatomic,assign) NSUInteger someNumber;
ClassB Method:
-(void) classBMethod {
[(ClassA*)self setSomeNumber:5];
}
As others have mentioned, if you are dealing with a subclass you should be fine but by the looks of your code I am guessing you would probably be better off with a protocol implementation see http://developer.apple.com/library/ios/#referencelibrary/GettingStarted/Learning_Objective-C_A_Primer/_index.html for an overview.
If that isn't a good fit then you may want to look at calling respondsToSelector first to see if the call will work. http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject/respondsToSelector:
But overall, you shouldn't be casting self to another class....
A cast tells the compiler that the variable represents a certain type, even though it is not declared as such. It will get rid of compiler warnings, but it does not affect the compiled output. In this case, it is declaring that the instance of ClassB is actually an instance of ClassA so that it can call setSomeNumber:, but this will only work if the object actually implements that method. If the object is not a member of ClassA or a subclass, and its class doesn't implement the method, your program will crash at runtime.
Is ClassB a subclass of ClassA? If it is, no cast should be necessary.
You can cast any pointer to any class you want to disable a warning that it may not respond to the selector, but if it doesn't respond to the selector at runtime, your app will crash when it tries to call that method and the class does not respond.

How to provide additional custom implementation of accessor methods when using #synthesize?

I want to fire some code when a property is accessed and changed. I use #property and #synthesize in my code for my ivars. The properties are retained, so I'd like to keep that memory management stuff automatically generated by #synthesize.
However, I assume that #synthesize tells the compiler to generate the accessor methods code right where #synthesize is, so most of the cases at the top of the code, right?
And when I have a property foo, I get -setFoo and -foo methods. Could I then just make a method like this, to execute some more custom code when a property is changed?
-(void)setFoo {
// custom stuff
}
Now that's a problem. How to execute the first one? I wouldn't love to have a different name here. Is there maybe a way to let the #synthesize directive create other names for getter and setter methods, which I then call easily? And I would still be able to use the dot syntax then to access them?
You can use #property and #synthesize just like you normally would, but provide a custom setter or getter (or both) and those will be used instead. Typically I will do something like this:
// Override the setter
- (void)setName:(NSString *)aName
{
if (name == aName)
return;
[name release];
name = [aName retain];
//custom code here
}
When I use the set property, it will invoke my custom method. However, the get will still be synthesized.
If you provide an implemnetation for the setters or getters it will use that instead of the generated implementation. Its not hard to implement the "retaining" aspect of the getters and setters that are generated for you by the compiler when u synthesize, so you can just write your own getters and setters i would say and go with that.
One wacky solution is to create an abstract super class that does gives you the normal property synthesis.
Then create a concrete subclass that you will actually use, and that simply implements and override method (same signature) and calls super to do the actual setting.
This allows you to do whatever you want to do before or after the call to super's implementation.
Example:
#interface ALTOClassA : NSObject
#property NSString *catName;
#end
Nothing else needed in the .m beyond the stubbed file for this test.
Create the subclass, nothing needed specially in the #interface
#import "ALTOClassA.h"
#interface ALTOClassAJunior : ALTOClassA
#end
In the #implementation we do our override.
#import "ALTOClassAJunior.h"
#implementation ALTOClassAJunior
- (void)setCatName:(NSString*)aCatName {
NSLog(#"%#",NSStringFromSelector(_cmd));
[super setCatName:aCatName];
NSLog(#"after super: self.catName %#", self.catName);
}
#end
In use:
ALTOClassAJunior *aCAJ = [ALTOClassAJunior new];
NSLog(#"aCAS.catName %#", aCAJ.catName);
NSLog(#"set it to George.");
[aCAJ setCatName:#"George"];
NSLog(#"aCAS.catName %#", aCAJ.catName);
This allows you to leverage the autogenerated code, and still do stuff you want to do with your class. Abstract Super Class is often a useful solution for many things.
Yes, in your #property declaration, you can specify the getter and setter methods.
#property (readwrite,getter=privateGetFoo,setter=privateSetFoo:) NSObject * foo;
In your foo and setFoo: methods, call [self privateGetFoo] or [self privateSetFoo:f] then your custom code.
The object can also set an observer on itself with addObserver:forKeyPath:options:context:.
That said, I don't think either of these are very clean ways to do things. Better to write your own getter/setter as others have suggested.