Why do variables initialized in viewDidLoad not retain value in Objective-C? - iphone

I have a class I wrote called Location that just holds some strings. I'm using two instances of that class in a view controller, and when I initialize the two variables in viewDidLoad, they work fine for that method, but then when I try to use them later they are null. I have them set as retained properties. I have tested them and know that they are initialized for viewDidLoad (I use their fields in the view). Do I have to do something special in the Location class to make sure they don't get released? When I re-initialize them in a different method, everything runs smoothly.

Instance variables properly initialized in viewDidLoad should retain values normally just like they would in any other method. A coding error may cause the issue you are describing, e.g. if you have local variables in viewDidLoad hiding identically named instance variables.

you (or the event loop) is probably releasing the objects you are initializing after viewDidLoad is complete since they are autoreleased or something. To prevent that, make the variables in question properties on the class with the "retain" attribute and set them to nil on dealloc.

Related

Accessing an instance variable from a background thread

Say I have an instance variable MyObject that has been allocated and initialized. Then say I do this:
[backgroundThread performBlock:^{
//do something with MyObject that might take some time
}];
[self dismissModalViewController]; //this releases all instance variables, right?
So what happens is I have an NSManagedObjectContext called backgroundThread that does some work on an object in the background. This returns immediately and does the work in the background, and then dismissModalViewController is called, which deallocates all instance variables. So what if the modal view has now been dismissed, but the backgroundThread still needs to use the object? Is this an issue? What is the workaround?
And another thing: This MyObject is inserted into the managed object context backgroundThread. Does this mean that this NSManagedObjectContext will retain the object, even after dismissing the view?
I'm using ARC.
There are several things you need to think about here. First keep in mind that the block will capture whatever it refers to. So you might not need to do anything special and your code will work fine, depending on exactly what you are doing in your block. The rules for block capture are described in Apple's Block Programming Topics documentation and how each variable is treated depends on its type. In particular,
In a manually reference-counted environment, local variables used within the block are retained when the block is copied. Use of instance variables within the block will cause the object itself to be retained. If you wish to override this behavior for a particular object variable, you can mark it with the __block storage type modifier.
If you are using ARC, object variables are retained and released automatically as the block is copied and later released.
Another thing to consider is that access to the instance variables may or may not be thread safe. Accessing the instance variables through properties declared as atomic is a step in the right direction, but you may need to use mutex locks or other techniques to synchronize access depending on the specifics on the situation.
If you want to reference ivars or other properties of your (modal) view controller, you need to insure that the modal view controller still exists.
Here's a potentially useful hint from Apple's documentation on dismissModalViewControllerAnimated::
If you want to retain a reference to the receiver’s presented view
controller, get the value in the modalViewController property before
calling this method.
Another idea that might work would be to create & instantiate a separate object that encapsulates the data / objects you want to access from either the view controller, or any other thread.

Set UITextFieldDelegate & release after UITextField dealloc, self contained

I have created a class that implements UITextFieldDelegate so I only need to use [MyDelegateClass setDelegate:textField someConfigparams:...] in order to use it. Inside it will create an object and assign to the textFieldDelegate.
The problem appears when releasing: the setDelegate method in UITextField doesn't retain the object so I can't just autorelease it. I could keep a reference outside to release it but it is ugly and prone to error since I need to do an extra work outside the delegate class. Subclassing UITextField is a bad option since I would need to use always this subclass which could conflict with others.
Is there any way I could release the delegate object when UITextField object is destroyed without relying to code outside MyDelegateClass?
I assume [MyDelegateClass setDelegate:textField someConfigparams:...] creates and instance of MyDelegateClass and assigns that instance as the delegate on the provided textField. What i would do is make the instance of MyDelegateClass a singleton, meaning there is only ever 1 instance.
Basically what will happen in this case is that MyDelegateClass will retain a strong reference to a single static instance of itself and that instance will stay alive for as long as your application stays alive or until you purposefully release it. It is perfectly ok to have one instance of an object be the delegate for many textFields. The memory impact of having a single instance of this class alive always is going to be constant, i.e. not growing, and very small.

Why not use self. call inside class

I've read google's and apple's code guide, they both access instance variables without self. call(getter and setter) inside the method implementation even though they have declared a property for that instance variable.That's why?
In my opinion, using self. call to set and get instance variables inside the method implementation of class makes it easier to manager retain count.
Is there any caveat to use getter and setter inside class?
It depends. You should always use the accessor in normal use.
However for init and dealloc methods, you should instead use the direct ivars to release and set variables. That's because the setters can have side effects that are not good to trigger during class initialization or deallocation.
In practice using an accessor as part of init probably will not cause an issue. But I have seen a number of real world crashes where a custom setter was not expecting nil and so use of the accessor in dealloc crashed the app. Even if it didn't crash it could be doing a lot of pointless work since the class was about to die.

What's the best way to have functions share an array in Objective-C?

I understand that in Objective-C you declare an array in the header file and interact with it in a class. So far I'm adding things and fetching them fine within a single function. I'm new to the language however and can't figure out how to share that array across other functions.
I'd like to initialize array data in my viewDidLoad and access it from various functions later on. Is this possible and if so what's the best way to do it?
Like you said, declare the array in the view controller's header file and make it a #property. Use alloc-init in the implementation's -viewDidLoad method to set it up. Deallocate it in the dealloc method. Use its property setter (self.array) to retain or assign another array, depending on the #property attribute. Access it directly (array) throughout your methods in your class implementation, and via its property getter (obj.array) from other classes.

Should I alloc an NSMUtableArray instance variable?

This is probably a silly question but I have been thinking it over for a while with no obvious answer.
I have a small app that I have been working on and am having a problem with my NSMutableArray instance variable. It was always (null) until I added an [[NSMutableArray alloc]init] to the viewDidLoad.
I am pretty new to the Objective C world so I am trying to get an understanding of this issue. I was under the impression that with I instantiated my class the instance variables were all alloc'd. When I add items to the array without the alloc/init it remains (null) with a retain count of 0.
The array in question was declared as a (retain) property.
I can add code if this isn't clear.
Any instance variables that are objects are actually just pointers that are initialized to nil (0). That is why the item isn't retained and added to the array, since messages to nil objects return nil/0.
You need to alloc and init the object in your class's init, and then release it in the dealloc.
The retain/assign/copy qualifiers on the property declaration are about how the memory for the property value is managed in the getters and setters that the compiler synthesizes for you. (The documentation discusses them in detail, and gives example code for each kind.)
That's completely orthogonal to whether your instance variables are initialized for you or not. Declaring an ivar is just reserving storage for the value; for Objective-C classes, that's a pointer to an instance. The runtime will initialize those ivars to zero for you, but you're still responsible for creating the objects you want to store there. (The same is true in similar languages like Java or C#: declaring an Array instance variable just gives you space for a reference, it doesn't create the array for you.)