I know that self is retained by a block if its being referenced inside a block. But if I am doing like this:
NSLog(#"%#",self.memberVariable);
Will memberVariable also be retained by the block? or only self is retained by the block?
Thanks in Advance.
The member variable also retained.According to Block programming guide,
In a reference-counted environment, by default when you reference an
Objective-C object within a block, it is retained. This is true even
if you simply reference an instance variable of the object. Object
variables marked with the __block storage type modifier, however, are
not retained.
The only "variable" you are "accessing" is self. Blocks only "capture" local variables (self is considered a local variable), because those are the only variables whose lifetime is tied to scope. Properties (which are really method calls) and instance variables are always "accessed" through some other object pointer, and thus their lifetime is associated with that object's lifetime.
Related
Let's say I have a method that returns an object pointer
-(MyObj *) returnMyObj {
MyObj *obj = [MyObj alloc] init];
return obj;
}
If I call this function without assigning the pointer like this
Scenario 1
[self returnMyObj];
and if I call this function with assignment to a pointer like this
Scenario 2
MyObj* obj = [self returnMyObj];
Compiler can release the object at the end of the returnMyObj method call in the Scenario 1 but it cant do the same in Scenario 2.How does ARC decide if it needs to retain the created object at the end of method invocation or not in both cases?
Here is what the ARC article in the documentation has to say:
To make sure that instances don’t disappear while they are still needed, ARC tracks how many properties, constants, and variables are currently referring to each class instance. ARC will not deallocate an instance as long as at least one active reference to that instance still exists.
To make this possible, whenever you assign a class instance to a property, constant, or variable, that property, constant, or variable makes a strong reference to the instance. The reference is called a “strong” reference because it keeps a firm hold on that instance, and does not allow it to be deallocated for as long as that strong reference remains.
ARC decides which objects will be kept in memory and which will be deallocated by counting the strong references to the objects.
In your second scenario you are creating a strong reference to the MyObj instance and ARC will not deallocate it while the object is in use. In this case it will be deallocated when the method that uses this object finishes.
The optimizer may absolutely release the object in scenario 2 at the end of the statement if obj is not referenced later in the block.
The whole point is that the optimizer can see when the pointer is referenced, and may release it as soon as the last reference is completed. obj does not have precise lifetime semantics, so it only extends the life of the object until the last time obj is referenced, not when obj goes out of scope.
In scenario 1, the reference is not assigned to any variable, so it clearly has no later references, and may be immediately released. That said, it may not immediately release the object, since returnMyObj does not transfer ownership to the caller (due to its name). So the object may not actually be released until the autorelease pool drains.
I know blocks in Obj-C allow you to reference local variables, which is nice. But can we safely pass local variables to another method from inside of a block?
I know referencing self can be dangerous from inside blocks, but does this extend to any other variables.
Example:
-(void)methodTakesObject(ObjectA *)object {
ObjectB *b = object.b;
__weak MyObject *weakSelf = self;
[b doInBackground:^(NSArray *results) {
[weakSelf doSomethingElseWith:results andWith:object andEvenWith:b];
}
}
There are three "types" of local variables here. the results from the block, the ObjectB created inside the method, and an ObjectA which was passed to the method to start.
Should I be concerned about using any of these variables, and indeed is there any difference/concerns between how these variables are treated from within the block
In fact, it makes no difference no matter what variables are involved.
The concern with a retain cycle is if an object holds a strong reference to a block that it isn't expected to release until it is deallocated while the block holds a strong reference to that same object. That's not happening here.
A method called -doInBackground: seems like it will run the block (starting immediately-ish) and then release the block when it finishes. So, there's no prospect of the block being kept around as long as some other object exists, thus there's no prospect of it keeping that other object around forever.
You don't even need to use the weak-self convention to avoid a retain cycle here. You would only use it in the unlikely case that you really want to allow self to sometimes be deallocated before the block calls its method. More likely, you should just use a normal, strong reference to self because it's normal and/or desirable for self to live long enough for the block to execute.
If you are worried about retain cycle, #ken gave you the perfect answer. As for the concerns about variables:
object is retained from the method that called
methodTakesObject: so you don't have to worry about it. (if it isn't nil, tho).
b is also retained by you, the reference count is likely 2 or
more, so you also don't have to worry about it.
In other words, you are safe.
I'm using RestKit to develop a RESTful application. I have a wrapper object that actually handles requests and even acts as the delegate for the RKObjectManager. I am experiencing an issue related to how ARC handles instance variables and retaining them, and it is clear to me that I do not understand how ARC works.
So when I do this, it fails (with error related to message sent to deallocated instance)
MyTestClient *testClient = [[MyTestClient alloc] init];
but when I declare a property and do this, all is fine:
self.testClient = [[MyTestClient alloc] init];
From what I understand, under ARC, an instance variable is always strong by default, but it's lifecycle is the scope of the method in which it's declared.
Since I can't do [testClient retain], is my only option to make it a property?
Your variables are strong by default and will be retained within their scope. So in the first example, the object will only be retained until the end of the function. In the second, since you have an instance variable, it will be retained until the owning object is deallocated (presumably long enough for you in this case). Your best option is to make it a property, but you could also just make it an instance variable. It will do the same thing for you in this case.
A simple way to think about it is you need to have a strong pointer to an object until you no longer need it around.
The equivalent to retain in ARC would be to have a pointer pointing to it. As long as you have something pointing to the object, that object will be kept alive. Hence you can use properties, instance variables, even instances pointing to those objects.
Like wbyoung said. You are getting the error because testClient is only alive inside where you initiated it, this being viewdidload, or init, or w/e.
I have member variables in my custom UIViewController that are defined as 'assign' (not 'retain') like this:
#property (nonatomic, assign) UIButton* mSkipButton;
In my loadView method, I set the var, for instance self.mSkipButton, to an autoreleased alloc of the variable type. I then attach it to my controller's view essentially having the view reference count and release it as needed.
This concerns me, however, that I have the pointer stored in my member var and that it could be referencing released memory if the count decrements at some point. Is it better practice to instead declare the variable as 'retain' and then in the viewDidUnload method release the member var (or just set it to nil to release and make sure i don't have an address in there)?
Alternatively, could I simply set the member var to nil in viewDidUnload and not make it a retained variable?
Is it better practice to instead declare the variable as 'retain' and then in the viewDidUnload...?
Yes, use retain -- good instinct. In viewDidUnload, you'd typically just set it to nil via the ivar's setter: self.ivar = nil;
I find it easier to be aware of and manage object codependencies explicitly, than to deal with issues related to using assign. You can completely avoid the issues of holding an unmanaged reference.
Arguments can be made that assign would usually be fine here (and it is in some cases), but using assign can complicate object graphs and ownership for anyone working with the class. As program complexity grows (and the libraries you depend on change), it becomes increasingly difficult to track lifetimes of unmanaged references. Things tend to break, or operate differently on different hardware and software combinations. Attempting to manage the lifetime of an unmanaged object over a complex program or in a concurrent context is self abuse. Guaranteeing defined and predictable behavior/operation reduces bug counts.
That's a property, not a "member var" (known in Objective-C as an instance variable or ivar.)
The semantics of a property depend on how that property is going to be used. Generally speaking, you'll want your properties to be retained for the lifetime of your object. If the property is a connected IBOutlet, this will be done for you by the NIB loader; otherwise, you must be explicit and use the retain or copy attribute on the property.
For objects that are expected to own your object, a property should always be marked assign to avoid a retain loop. For example, an object usually owns any object for which it acts as a delegate (usually, but not always--every CS rule has an exception.)
Is it safe to count on ints always being initialized to 0 in Objective-C?
More specifically, when an object with int ivars has been newly instantiated, is it safe to assume that its ivars have value 0?
Yes, class instance variables are always initialized to 0 (or nil, NULL, or false, depending on the exact data type). See the Objective-C 2.0 Programming Language:
The alloc method dynamically allocates memory for the new object’s instance variables and initializes them all to 0—all, that is, except the isa variable that connects the new instance to its class.
EDIT 2013-05-08
Apple seems to have removed the above document (now linked to The Wayback Machine). The (currently) active document Programming With Objective-C contains a similar citation:
The alloc method has one other important task, which is to clear out the memory allocated for the object’s properties by setting them to zero. This avoids the usual problem of memory containing garbage from whatever was stored before, but is not enough to initialize an object completely.
However, this is only true for instance variables of a class; it is also true for POD types declared at global scope:
// At global scope
int a_global_var; // guaranteed to be 0
NSString *a_global_string; // guaranteed to be nil
With one exception, it is not true for local variables, or for data allocated with malloc() or realloc(); it is true for calloc(), since calloc() explicitly zeros out the memory it allocates.
The one exception is that when Automatic Reference Counting (ARC) is enabled, stack pointers to Objective-C objects are implicitly initialized to nil; however, it's still good practice to explicitly initialize them to nil. From the Transitioning to to ARC Release Notes:
Stack Variables Are Initialized with nil
Using ARC, strong, weak, and autoreleasing stack variables are now implicitly initialized with nil
In C++ (and C++ objects being used in Objective-C++), class instance variables are also not zero-initialized. You must explicitly initialize them in your constructor(s).
I don't think you should assume any values for initialization. If you are building logic around a "0" value, you should set it to be sure.
Yes, in C global vars are initialized to zero.
In Objective-C even local vars are initialized to zero.
You can count on it.