I have the following setter defined in my class that extends UICollectionView:
// #interface ClipsDataSource : NSObject <UICollectionViewDataSource>
- (void)setProject:(Project *)project
{
_project = project;
ClipsDataSource *dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];
dataSource.delegate = self;
dataSource.fetchedResultsController = project.clipsResultsController;
self.dataSource = dataSource;
}
When I run my application I get the following exception:
-[CALayerArray numberOfSectionsInCollectionView:]: unrecognized selector sent to instance 0x174245490
I realised that the instance pointer is the address of the local variable I had used in my setter; the class name is obviously random. From this "discovery" I reasoned that the object was released after assignment.
Normally Xcode will warn me about these issues by saying:
Assigning retained object to unsafe property; object will be released after assignment.
And, sure enough, I see that warning if I change my code to this:
self.dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];
I have two questions:
Why doesn't Xcode show a warning?
Why is .dataSource considered an unsafe property? It's defined as (nonatomic, assign).
1) Why doesn't Xcode show a warning?
Because clang is not intelligent enough to figure out that your datasource instance will not be retained elsewhere; only this obvious case will be reported:
self.dataSource = [[ClipsDataSource alloc] initWithCollectionView:self];
2) Why is .dataSource considered an unsafe property? It's defined as (nonatomic, assign).
This is done to prevent retain cycles with self referential constructs, which happens quite often in ViewController code.
Imagine that your CollectionViewController is the datasource of CollectionView,
self.collectionView.dataSource = self;
This means:
CollectionViewController retains .collectionView, because View Controllers retain their views by default.
CollectionView retains it's datasource (which is CollectionViewController).
This will cause a retain cycle and therefore Apple decided to use unsafe unretained pointer for .datasource.
Note that both assign and weak pointers will not retain the object that they are pointing. The difference between them is that weak will be automatically nullified when the referenced object is deallocated.
But assign pointer will NOT be nullified, so it will continue pointing to address of memory. Further dereference of that pointer (after deallocation) will probably cause EXC_BAD_ACCESS, or you will get another object (as another object can be written in that address after deallocation).
Related
I have a few questions about this code:
#import "ViewController.h"
#interface ViewController ()
#property (copy, nonatomic) NSArray *myArray;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.myArray= #[#"one", #"two", #"three", #"four"];
}
I know the self keyword means that's method will be sent to the receiver of that message, and I know when and how to use it if i was creating a simple command utility code, but when learning about creating an iPhone app and using the storyboard every time I see the self keyword it confuses me, I don't know which object is the receiver
2nd question, I know that #[#"object", #"object"];is quick way to create an NSArray object, but "myArray" is a property not an NSArray object. please explain, thank you.
myArray is. The name of a property, as you say. By default, the compiler will create an instance variable called _myArray that's used by that property. In any case, because you've declared the property to be of type NSArray * (and not readonly) you can assign an array to it.
The self keyword is simply a pointer to the "current" object, some instance of the class that you're writing code for when you type "self". If you assign something to self.myArray, the class in which you make that assignment needs to have a myArray property. In your code example, self is a pointer to the particular instance of ViewController that just loaded its view. None of that changes when you're writing an iPhone apportion using a storyboard. self is always the object receiving the method in which self is used. (Note: when used in a class method, i.e. one that starts with +, the object receiving the method is the class itself, not an instance of the class. Don't worry about this if it sounds confusing -- it doesn't come up all that often.)
If you find an expression like self.myArray confusing, it may help to know that property syntax is just shorthand for a method call. Also, self in an expression like that isn't special at all. The syntax is foo.bar where foo can any object pointer (including self) and bar can be any property of the object pointed to by foo. The expression translates directly to either [foo bar] or [foo setBar:...], depending on whether you're reading or assigning a value to the property. So,
self.myArray = #[a, b, c];
means exactly the same as:
[self setMyArray:#[a, b, c]];
self always corresponds to the self class. So every instance of a class will have its own self.
In your case myArray is a property of Class ViewController. Here you can refer to the property by using self.myArray or _myArray.
In the following statement you are creating an array with four strings and adding it to myArray.
self.myArray= #[#"one", #"two", #"three", #"four"];
Your wordings in the question :
I know the self keyword means thats method will be sent to the
receiver of that message
is valid for a method call where you use it as :
[self aMethod];
Even in this you are calling a method which is a part of the class. If you call any method which is not of the current(self) class then you call it by using that class' object name as:
SomeClass *someClassObject = ...
[someClassObject itsMethod];
"self" is a pointer to object to which the method belongs. In your case you may have many instances of ViewController and each of them can call viewDidLoad and in that method "self" is the pointer to the instance itself. To look at it from the C perspective you could create a method using pointer to function where you would also send own pointer to the function called "self", for instance void foo(MyClass *self); to call it then myClassInstance->foo(myClassInstance); this procedure kind of simulates methods but you always need to send instance pointer as well (self). So there should be no confusion as to what "self" is except it is more commonly known by "this" keyword. It is just a reference to the object on which the method is being called.
The property is just a convenience of usually 2 methods called getter and setter. When creating a property #property NSArray *myArray you will actually generate a pointer usually NSArray *_myArray; then a getter:
- (NSArray *)myArray {
return _myArray;
}
And a setter
- (void)setMyArray:(NSArray *)myArray {
_myArray = myArray;
}
How getters and setters are created depends on property attributes (strong, weak, readonly...). You may even override any of these methods or both. So as you stated "but "myArray" is a property not an NSArray object" a property can have truly any type.
I am getting used to using weak and strong references and when to use them and when not and I got to a case like described below (check the comment about the warning)
#interface MPIViewController ()
#property (weak, nonatomic) UIView *subview;
#property (weak, nonatomic) UILabel *label;
#end
#implementation MPIViewController
// ...
// some code here
// ...
- (void)viewDidLoad
{
[super viewDidLoad];
self.subview = [[UIView alloc] init]; // warning here: assigning retained object to weak property
self.label = [[UILabel alloc] init]; // no warnings
[self.view addSubView: self.subview];
[self.view addSubView: self.label];
}
// ...
// some code here
// ...
#end
From description of - (void)addSubview:(UIView *)view:
This method establishes a strong reference to view and sets its next
responder to the receiver, which is its new superview.
This means that this object won't be deallocated after method finishes as it's superview will retain it and hold a strong reference to it and therefore this view will be kept in memory for as long as its superview is there. Am I right here?
I am not sure also if I understand assigning here correctly. Warning says that it will be deallocated straight after the assignment but this sounds wrong as then it wouldn't be possible to assign any variable to a weak pointer as it would get deallocated in the next line of code?
For UILabel same assign works fine, however for UIView it doesn't? Does the compiler treat UIView somehow differently? This really puzzles me how that is even possible.
This code can be fixed easily just by assigning the UIView to a local method variable and then passing it to the setter like this:
UIView *tmpView = [[UIView alloc] init];
self.subview = tmpView;
Variables declared in the method are by default strong so having such a construction removes the warning as the compiler thinks that this variable has a strong reference so weak reference that is then assigned to will be kept as long as the method variable will point to it. BUT! how does that make sense as the tmpView is only a local method variable and will be dumped after method will finish?
To the first question:
Let's have a closer look to it:
self.subview = [[UIView alloc] init];
[UIView alloc] returns an instance with ownership +1. This is assigned to a (non-visible) strong reference, which build the self of -init. -init passes the ownership through. (This is not correct, if -init returns an instance which is not the original receiver, but for your case it is enough details.) So we can think of the return value of -init as an ownership transfer, too.
You assign this instance to a weak variable. In this moment it can be released. (Read: ARC does not promise to do it immediately, IIRC.) the instance variable can be nil before the object is hold by its superview. So this code is dangerous:
self.subview = [[UIView alloc] init];
// _subview can be nil'ed
[self.view addSubView: self.subview]; // add nil
I do not believe that this is your problem, but it can be a problem. – Thinking again about it, it is your problem. Read the edit at the end. –To get rid of it, simply use a strong local variable:
UIView *subview = [[UIView alloc] init]; // defaults to __strong
[self.view addSubView: subview]; // adds an ownership
self.subview = subview;
The second question:
I do not know, why the compiler gives you no warning in the second case. What does happen, if you repair the first case?
At runtime a different handling of both cases is possible, because it is undefined, when the first instance is released. Maybe as a part of optimization a pointer is reused. More detailed:
__strong id completlyHiddenCompilerGeneratedVar;
… = [(completlyHiddenCompilerGeneratedVar=[UIView alloc]) init];
… = [(completlyHiddenCompilerGeneratedVar=[UILabel alloc]) init];
The first instance would be dealloc'ed, when the second instance is created, because it overwrites the internal strong reference.
Again: Repair the first case and tell us, what happens with the second one.
An object need at least one strong pointer to it in order to be kept in memory.
So when you alloc it to a weak pointer that condition is not being met. Make your properties strong if you really need to access these views.
I have a class that creates an object lazily and stores it as a weak property. Other classes may request this object, but must obviously keep a strong reference to it to keep the object from being deallocated:
// .h
#interface ObjectManager
#property(nonatomic, weak, readonly) NSObject *theObject;
#end
// .m
#interface ObjectManager ()
#property(nonatomic, weak, readwrite) NSObject *theObject;
#end
#implementation ObjectManager
- (NSObject *)theObject
{
if (!_theObject) {
_theObject = [[NSObject alloc] init];
// Perform further setup of _theObject...
}
return _theObject;
}
#end
When the scheme is Xcode is set to build for Debug, things work just fine - an object can call objectManagerInstance.theObject and get back theObject.
When the scheme is set to build for Release, theObject returns nil:
// Build for Debug:
NSObject *object = objectManagerInstance.theObject;
// object is now pointing to theObject.
// Build for Release:
NSObject *object = objectManagerInstance.theObject;
// object is now `nil`.
My guess is that the compiler is optimising my code by seeing that _theObject is not used further in the accessor method itself, so the weak variable is being set to nil before returning. It seems that I would have to create a strong reference before actually returning the variable, which I can only think to do using a block, but would be messy and I'd rather avoid it!
Is there some kind of keyword I can use with the return type to stop the ivar from being nilled so soon?
Most likely, DEBUG builds cause the object to sit in the autorelease pool long enough to cause it to "work" whereas a RELEASE build causes the optimizer to do a bit more control flow analysis which subsequently eliminates the autorelease chatter.
Frankly, that the compiler isn't spewing a warning in the release build saying that the code can never work is a bug (please file it as you have a great, concise, example)!
You'll need to maintain a strong reference somewhere to the object until whatever needs a strong reference has an opportunity to take a reference.
I'm wondering if something like this might work:
- (NSObject *)theObject
{
NSObject *strongObject;
if (!_theObject) {
strongObject = [[NSObject alloc] init];
_theObject = strongObject;
// Perform further setup of _theObject...
} else {
strongObject = _theObject;
}
return strongObject;
}
I.e. the above would be more akin to a factory method that returns an autoreleased object while also maintaining a weak reference internally. But the optimizer might be too clever by half and break the above, too.
You're being bitten by the optimizer.
Since _theObject is a weak reference, the system is free to get rid of it, and zero out your weak reference, whenever it's not retained. But it's not required to do it right away.
In your lazy instantiator, the newly-created object is never retained. The optimizer sees this, and says "Wow! I can zero this reference at any time! Why don't I do it...right now!" And before you know it, you're returning nil.
What you want to do is assign the lazily-instantiated object to a local variable, for an implicitly strong reference that lasts for the scope of the function. You also want to tell the compiler that you really do want the full scope, using the objc_precise_lifetime annotation.
For details from the standard, see this page.
When I have code like the following:
self = [super init]
does self point to super? If so, why would you want this? if my instance object has the variable "someVal", I won't be able to get to it by doing [self someVal]. correct?
How then would I get to the instance variable's using self when self points to super?
does self point to super?
It's really the other way around. super is really the same as self, except that it tells the compiler to start looking for method implementations starting with the superclass rather than the class itself. You can check this by logging the value of super and the value of self; you'll find that they both point to the same address.
When you create an object, you do this:
Foo *f = [[Foo alloc] init];
The alloc allocates the memory that will become the object you're creating, but until that memory is initialized it's just a chunk of memory -- not a valid object. If Foo is a subclass of Bar and Bar is a subclass of NSObject, then by convention Foo's initializer will call Bar's, and Bar's will call NSObject's, so that the initialization proceeds in order: first the memory is initialized by NSObjects' -init, and Bar's init receives the returned value and assigns it to self. It then proceeds to do any Bar-specific initialization, and returns self. Foo's -init then assigns the returned value to self again and finally does any Foo-specific initialization.
All that assigning to self might seem both redundant and confusing. It's really just a convention, but the purpose is to allow the superclass's initializer to return some object other than the one that was allocated, including nil. So, for example, if the initialization of Bar failed for some reason, -[Bar init] could return nil. The possibility that nil might be returned from [super init] is the reason we put the self = [super init] assignment inside a conditional: if the assigned value is nil, the initialization part is skipped and nil is returned. It's also possible that -[Bar init] could return a pointer to an object other than the one that was allocated, such as when an object similar to the one being created already exists and can be reused.
Most of the time, the pointer you get back from -init will be the same one that you got from +alloc, so you could write this:
Foo *f = [Foo alloc];
[f init];
If you write that, however, you're making an assumption that the initializers of your class and all the classes that it inherits from will always return the same object, and will never return nil. By doing that you're breaking the convention and severely hamstringing yourself and whoever wrote the classes from which Foo inherits -- they'll break your code if they return a different object in a future release of the class. Also, it'll look like you don't know what you're doing.
does self point to super?
This question doesn't make sense in an instance method, since there super is not really a concrete/actual pointer-to-instance, it just indicates that the implementation of the superclass must be called. And since in the case of most objects (except class clusters) all methods return self;, then the answer is no: the actual pointer to the instance doesn't change magically by itself.
For the record: the exception is manifested by class clusters (most Cocoa container classes, for example, NSString, NSArray, etc.). These classes often have an initializer method that returns a different instance than the one that was originally allocated, and of which the class is a concrete subclass of the class of the original self. For example, an implementation of the NSString initializer could be:
#implementation NSString
- (NSString *)init
{
[self release];
self = [[__NSCFString alloc] init];
return self;
}
#end
The reason for this is that optimizing for different types of initialization can be achieved this way.
Self is always pointing to one instance. When you use super you are referencing parent methods not a parent instance.
self means current class' instance.
self = [super init] means self is getting the value returned by [super init].
Why would I use (inside my dealloc method)?
[myInstance release] instead of [self.myInstance release]
myInstance = nil instead of self.myInstance = nil
Although we use self.myInstance = [[[AClass alloc] init] autorelease] instead of myInstance = [[[AClass alloc] init] autorelease]?
Those practices are from numerous examples I see on the web.
1) [myInstance release] instead of [self.myInstance release]
prefer the former.
the returned value of self.myInstance is defined by implementation when a subclass has overridden the method myInstance. you're not interested in the behaviour of the interface of a constructed object during dealloc (since a subclass may override and return something other than your ivar).
what you are interested in dealloc is releasing the references you own before your object is destroyed. if the subclass has overridden myInstance, then it could:
a) return an ivar (declared in the subclass) that's already been released
or
b) the implementation of the override may return a newly created autoreleased object
either a or b could lead to an over-release and a crash (assuming everything else is correctly retained/released). this also suggests why you should assign nil to the ivar after releasing it.
this is also a classic example of how to trigger object resurrection. object resurrection occurs when an implementation of the getter/setter you call recreates its state after it's already been deallocated. the least offensive side-effect would cause a harmless leak.
2) myInstance = nil instead of self.myInstance = nil
again, prefer the former.
a formal response would look much like the response to #1 -- the rationale, side-effects and dangers apply here as well.
the safest way to handle this is to access the ivar directly:
[myInstance release], myInstance = nil;
because there may be really nasty side-effects (crashes, leaks, resurrection) which may be difficult to reproduce.
these dangers may be easily avoided and your code will be far easier to maintain. on the other hand, if people encounter the side-effects when using your programs, they will probably avoid (re)using it wherever they can.
good luck
Calling self.myInstance = uses the auto generated setter method. Calling [self.myInstance release]; calls release on the object returned by your getter method. It all depends on how your properties were set up (retain, assign?). There is no necessarily right or wrong answer to your question, since it all depends on the property in question. I suggest you read up on Objective C properties to get a better feel for this kind of thing.
And, unless myInstance was declared with assign, you wouldn't want to call self.myInstance = [[AClass alloc] init] You'd be much better off with self.myInstance = [[[AClass alloc] init] autorelease]
Note that using
myInstance = nil
instead of
self.myInstance = nil
Is incorrect (in the context of say a viewDidUnload method in a UIViewController subclass) if myInstance is a retain property, since if myInstance points to an object, it will be leaked!
This depends on a property that you defined in interface. For example if you define retain property:
#property (nonatomic, retain) NSObject *property;
then you may use just self.property = nil; in dealloc method, because it equals to:
[property release]; // releases previous property
property = [nil retain]; // [nil retain] returns just nil
The very same thing with self.property = [[A alloc] init];. This equals to
[property release]; // releases previous property
property = [[[A alloc] init] retain];
in case of property = [[A alloc] init]; property won't be retained.
Here's a full properties guide form Apple.
Actually using
self.myInstance = [[AClass alloc] init];
will lead in a memory leak, cause self.myInstance is using setter methods which leads in retain +1 along with alloc/init retain +1. So you'll get a retain count +2;
... = self.myInstance
and
self.myInstance = ...
are actually subroutine or method calls to getters and setters, which depending on how you define these subroutines, or have Objective C Properties create them, could do almost anything.
If the case of retain properties, the subroutines might play with the retain counts. If you do your own getters and setters, you could have them control the lights in your house, turning them on for none zero sets and turning the lights out when setting something to zero or nil. There doesn't even need to be a backing variable named "instance" which could be set by:
instance = ...