Recommended way to declare delegate properties with ARC - objective-c

I used to declare all delegate properties as
#property (assign) id<FooDelegate> delegate;
I was under the impression that all assign properties should now be weak pointers, is this correct?
If I try to declare as:
#property (weak) id<FooDelegate> delegate;
I get an error while trying to #synthesize (autogenerated weak properties are not supported).
What's the best practice in this case?

Xcode 4 Refactor > Convert to Objective-C ARC transforms:
#interface XYZ : NSObject
{
id delegate;
}
#property (assign) id delegate;
...
#synthesize delegate;
into:
#interface XYZ : NSObject
{
id __unsafe_unretained delegate;
}
#property (unsafe_unretained) id delegate;
...
#synthesize delegate;
If I remember correctly it is also mentioned in WWDC 2011 video about ARC.

Use __unsafe_unretained instead weak for ARC projects targeting iOS 4 and 5. The only difference is that weak nils the pointer when deallocated, and it's only supported in iOS 5.
Your other question is answered in Why are Objective-C delegates usually given the property assign instead of retain?.

Related

#property hides _ivar when setter and getter are custom [duplicate]

This question already has answers here:
Adding a getter makes using an underscore incorrect syntax
(3 answers)
Closed 7 years ago.
#import "AppDelegate.h"
#interface AppDelegate ()
#property (strong, readwrite, nonatomic) NSNumber *currentNumber;
#end
#implementation AppDelegate
- (NSNumber *)currentNumber {
}
- (void)setCurrentNumber:(NSNumber *)currentNumber {
}
Why I can't access _currentNumber in currentNumber?
If I will remove setCurrentNumber then I can access _currentNumber in currentNumber?
The #property does not cause the ivar generation; rather, it's the implicit #synthesize. However, when you implement both the getter and setter, there is nothing to (implicitly) synthesize, so clang doesn't bother. If you add an explicit #synthesize statement, you'll get your ivar.
Like Avi mentioned, there is #synthesize keyword. If you just declare property(without implementing getter and setter for it) the corresponding ivar will be generated. Its name will be [underscore][property_name].For example declaring #property currentNumber; leads to implicit applying `#synthesize currentNumber = _currentNumber;
But if you want to assign ivar with another name to your property you can declare this ivar and synthesize the property with it:
#interface AppDelegate ()
{
NSNumber *_anotherIvar;
}
#property (strong, readwrite, nonatomic) NSNumber *currentNumber;
#end
#implementation AppDelegate
#synthesize currentNumber = _anotherIvar;
#end
#synthesize tells the compiler to create corresponding getter and setter which are backed by ivar on the right side of assignment. And if you provide your own setter - you prevent compiler from creating implicit synthesize(and generating ivar), so you need to provide ivar by yourself somehow(for example use explicit synthesize).
Here is good explanation about #synthesize.

Objective-C existing instance variable must be __unsafe_unretained error [duplicate]

This question already has an answer here:
Existing ivar 'title' for unsafe_unretained property 'title' must be __unsafe_unretained
(1 answer)
Closed 9 years ago.
Same code are already questionned here, but I deal with a different problem that I can't solve myself probably because i'm new with Objective-C, so I decide to ask the question :)
webberAppDelegate.h:
#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
#interface webberAppDelegate : NSObject <NSApplicationDelegate> {
NSWindow *window;
WebView *webber;
}
#property (assign) IBOutlet NSWindow *window;
#property (assign) IBOutlet WebView *webber;
#end
webberAppDelegate.m:
#import "webberAppDelegate.h"
#implementation webberAppDelegate
#synthesize window;
#synthesize webber;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSString *urlString = #"http://www.apple.com";
// Insert code here to initialize your application
[[webber mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]];
}
#end
So, in webberAppDelegate.m, here's my problem with this fraction I suppose:
#synthesize window;
#synthesize webber;
who give me this long error:
Existing instance variable 'window' for property 'window' with assign attribute must be __unsafe_unretained
and pratically the same for other var "webber":
Existing instance variable 'webber' for property 'webber' with assign attribute must be __unsafe_unretained
Thanks for your help, I really appreciate Stackoverflow community for days !!
The default ownership qualification for instance variables in ARC is strong, and like #robMayoff mentioned assign is the same as unsafe_unretained so your code reads like the following:
#interface webberAppDelegate : NSObject <NSApplicationDelegate> {
__strong NSWindow *window;
__strong WebView *webber;
}
#property (unsafe_unretained) IBOutlet NSWindow *window;
#property (unsafe_unretained) IBOutlet WebView *webber;
As mentioned in the linked answer provided by #Firoze, the property declaration and iVar should have matching ownership qualification. So the solution would be to make the __strong in the above code to __unsafe_unretained or to remove the instance variable declarations completely so that the compiler takes care of it.
The same solution is provided in the linked answer in the comment. Just adding some info.

Can't get custom #protocol working on iOS

Note: the below is using iOS with Automatic Reference Counting (ARC) enabled. I think ARC may have a lot to do with why it isn't working as this is set up as per examples i've found via google.
I am trying to create a protocol to notify a delegate of the filename the user selects from a UITableView.
FileListViewController.h
#protocol FileListDelegate <NSObject>
- (void)didSelectFileName:(NSString *)fileName;
#end
#interface FileListViewController : UITableViewController
{
#private
NSArray *fileList;
id <FileListDelegate> delegate;
}
#property (nonatomic, retain) NSArray *fileList;
#property (nonatomic, assign) id <FileListDelegate> delegate;
#end
FileListViewController.m
#import "FileListViewController.h"
#implementation FileListViewController
#synthesize fileList;
#synthesize delegate;
This gives an error at the
#synthesize delegate;
line which is "FileListViewController.m: error: Automatic Reference Counting Issue: Existing ivar 'delegate' for unsafe_unretained property 'delegate' must be __unsafe_unretained"
If i change FileListViewController.h putting __weak and (weak) then it will run.
#protocol FileListDelegate <NSObject>
- (void)didSelectFileName:(NSString *)fileName;
#end
#interface FileListViewController : UITableViewController
{
#private
NSArray *fileList;
__weak id <FileListDelegate> delegate;
}
#property (nonatomic, retain) NSArray *fileList;
#property (weak) id <FileListDelegate> delegate;
#end
But when I try to set the delegate the app crashes. A view called 'ImportViewController' is creating a view from 'FileListViewController' and setting the delegate to itself (ImportViewController) so I can implement my custom protocol of 'didSelectFileName'. The error I get is;
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ImportViewController setDelegate:]: unrecognized selector sent to instance 0x6c7d430'
The code I am running is;
ImportViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
FileListViewController *fileListViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"filelist"];
[fileListViewController setDelegate:self];
[self.navigationController pushViewController:fileListViewController animated:YES];
}
My Questions are:
Why does putting (weak) and __weak in make it work? I don't
understand why this works as I found it googling and there wasn't an
explanation.
Why can't I set my delegate using this
'[fileListViewController setDelegate:self];' ? It seems like the
compiler doesn't know 'delegate' exists.
Under ARC ivars default to strong. So the error
Automatic Reference Counting Issue: Existing ivar 'delegate' for unsafe_unretained property 'delegate' must be __unsafe_unretained"
is telling you that you've declared a property with __unsafe_unretained (assign) ownership, where the underlying ivar has __strong ownership, which is illegal. To avoid the error, you have 3 options:
Omit the ivar. It's not necessary to declare an ivar for a synthesized property. The ivar will be declared implicitly with ownership matching your property.
Define the ivar to match your (assign) property declaration: __unsafe_unretained id <FileListDelegate> delegate;
Define the property to match the ivar's implicit __strong ownership: #property (weak) id <FileListDelegate> delegate;
Personally, I'd omit the ivar declaration so you have the ownership semantics in one place, on the property declaration.
It seems that with :
FileListViewController *fileListViewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"filelist"];
you didn't get an FileListViewController object. Look at the message it says :
-[ImportViewController setDelegate:]: unrecognized selector sent to instance 0x6c7d430
and that why your app crashes. Also try to define a retain property, instead of just assign, in case the delegate is deallocated elsewhere, your app won't crash.
I just ran across this same issue, forcing me to finally delve into the ARC documentation.
Also try to define a retain property, instead of just assign, in case the delegate is deallocated elsewhere, your app won't crash.
To maybe clarify the above quote from user756245 's answer, based on my reading I don't think that iOS 5 has changed the best practice that you shouldn't be retaining your delegate as this is a good way to leak. I think the __weak and (weak) tokens are annotations for the compiler for the sake of being able to correctly deal with generating code for the delegate.

Overriding properties which conform to protocols

I seem to be getting a new error when using LLVM Compiler 2.0, which I haven't had before.
I have a protocol called DTGridViewDelegate defined as:
#protocol DTGridViewDelegate <UIScrollViewDelegate>
I have a property called delegate on DTGridView (a subclass of UIScrollView, which itself has a delegate property). This is defined as:
#property (nonatomic, assign) IBOutlet id<DTGridViewDelegate> delegate;
Now the message I get is:
DTGridView.h:116:63: error: property type 'id<DTGridViewDelegate>' is incompatible with type 'id<UIScrollViewDelegate>' inherited from 'UIScrollView'
Because I had said that the DTGridViewDelegate conforms to UIScrollViewDelegate, I thought that this would be ok to override this property in this way, and indeed this is the first compiler to suggest there is a problem.
I have fixed the error by declaring the property as such:
#property (nonatomic, assign) IBOutlet id<DTGridViewDelegate, UIScrollViewDelegate> delegate;
I am wondering whether this is a compiler issue?
Your setup looks like the same one used in the case of UITableView inheriting from UIScrollView. The UITableViewDelegate protocol inherits from UIScrollViewDelegate protocol.
I set up the following which compiles fine:
// .h
#protocol ParentClassDelegate
-(NSString *) aDelegateMethod;
#end
#interface ParentClass : NSObject {
id delegate;
}
#property(nonatomic, assign) IBOutlet id <ParentClassDelegate> delegate;
#end
//.m
#implementation ParentClass
#synthesize delegate;
-(id) delegate{
return #"Parent delegate";
}//-------------------------------------(id) delegate------------------------------------
-(void) setDelegate:(id)someObj{
delegate=someObj;
}//-------------------------------------(id) setDelegate------------------------------------
#end
//.h
#protocol ChildClassDelegate <ParentClassDelegate>
-(NSArray *) anotherDelegateMethod;
#end
#interface ChildClass : ParentClass{
}
#property(nonatomic, retain) IBOutlet id <ChildClassDelegate> delegate;
#end
//.m
#implementation ChildClass
//#synthesize delegate;
-(id) delegate{
return #"childDelegate";
}//-------------------------------------(id) delegate------------------------------------
-(void) setDelegate:(id)someObj{
delegate=someObj;
}//-------------------------------------(id) setDelegate------------------------------------
#end
Not sure what is causing your problem. I would note that in the header the UITableViewDelegate protocol looks like:
#protocol UITableViewDelegate<NSObject, UIScrollViewDelegate>
... so maybe the compiler likes things more explicit sometimes.
I would suggest a clean and build. That solves a lot of problems.
Since there isn't a formal Objective-C language specification, it's impossible to say whether the compiler is behaving properly. All we can say is that Apple's gcc doesn't seem to have a problem with the above scenario, though it's conceptually unsound as it can break Liskov substitution, since delegate is covariant from UIScrollView to DTGridView (though covariance is just as much a problem). What would happen if you passed a DTGridView to code expecting a UIScrollView, which then proceeded to set delegate to an object that conformed to UIScrollViewDelegate but not DTGridViewDelegate?

How to define and implement properties in protocol

I want to define one protocol with few properties and need to use those properties in another NSObject subclass. Please give me link or example code. I need that to work with 10.5.
Thanks
PLEASE CHECK THE FOLLOWING SAMPLE CODE
#protocol MyProtocol
#property (nonatomic, readonly) id someObject;
#property (nonatomic, getter=isAlive) BOOL alive;
#end
#import "MyProtocol.h"
#interface MyCustomClass : NSObject <MyProtocol>{
}
#end
#import "MyCustomClass.h"
#implementation MyCustomClass
#synthesize someObject,alive;
/*
- (id)someObject {
return nil;
}
- (BOOL)isAlive {
return YES;
}
- (void)setAlive:(BOOL)aBOOL {
}
*/
#end
**Added:
Compling code with x86_64 architecture works fine. But error if i'll change the architecture to i386, then i am getting following warnings:
MyCustomClass.m:13: error: synthesized property 'someObject' must either be named the same as a compatible ivar or must explicitly name an ivar
error: synthesized property 'alive' must either be named the same as a compatible ivar or must explicitly name an ivar
I just want to know why it is working in x86_64 with #synthesize and not in i386.**
#property just says to the compiler that the class is expected to define the methods to match that property.
#protocol MyProtocol
#property (nonatomic, readonly) id someObject;
#property (nonatomic, getter=isAlive) BOOL alive;
#end
Anything implementing that protocol will now need to have
- (id)someObject;
- (BOOL)isAlive;
- (void)setAlive:(BOOL)aBOOL;
I think the things you're dealing with are primarily side effects of the introduction of Objective-C 2.0. It lets you do things like declare properties without also defining instance vars. But (as you have discovered), it is only x86_64 and post-10.5 compatible.