Accessing an instance variable from a background thread - iphone

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.

Related

ARC delegate issue

I need to download some images from server. So I created a seperate class to handle NSURLConnection delegates.
At the end of didFinishDownloadingData, I called a delegate method like [(id)delegate performSelectorselector(finished:) withObject:receivedData]
I have a view controller called ListImages.
I created the above connection class from ListImages class and assigned connection.delegate = self. After image loaded from server the method -(void)didFinishDownloadingData:(NSData *)data; was called successfully, and I could display that image.
My problem starts now. To handle some common tasks, I created a new class called SharedMethods which is a subclass of NSObject. I allocated connection class as
Connection *conn = [[Connection alloc]init];
conn.delegate = self;
[conn startDownload]; //called a method which starts nsurlconnection.
I am using ARC so not released that object. My applicaion got exception in method, (In Connection class)
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[(id)delegate performSelectorselector(finished:) withObject:receivedData]; //Got an exception in this line
}
The exception was [SharedMethods retain] message send to deallocated object. I dont think I have released anything because I am using ARC.
There was also a problem while callingUIAlerView delegates inside a Class which is a subclass of NSobject. It is not called any how. My doubt is, is there any problem with using a NSObject sublass? Is there anything to consider when using NSObject sublass ?
Thanks in advance.
Using ARC doesn't mean than objects never receive the release method, or that they never get deallocated. It just means that you don't have to make explicit calls to retain and release, and that happens automatically.
The problem here is that your objects are getting deallocated because no one is owning them. Your specific problem is that SharedMethods is being deallocated because it's not getting retained, but I can't show you how exactly that's happening because you didn't post the relevant code.
I can, however, show you that you're not managing your Connection properly, and hopefully that can help you figure out what you're doing wrong with SharedMethods.
So you create Connection with alloc init, which with retain-release code would give it a retain count of 1, but since you're not using ARC anymore that's not really relevant. Unless some other object asserts ownership of the Connection, ARC will automatically insert a call to release to bring the retain count back to 0 (it's kind of like if ARC automatically inserted an autorelease).
Since you don't assign Connection to a strong or retain property, or put it in a collection, no other object is asserting ownership to it. So once execution reaches the end of the scope where the variable conn is defined, it will get released and deallocated.
So in ARC, much like in manual retain-and-release code, you still need to make sure objects are owned by some other object in order for them to stick around. The only difference is that you don't need to manually call retain and release, you just have to think about the object ownership graph—which object is owned by which other object—and make sure that any object you want to stick around is owned by some other object.
So to reiterate, you need make sure that SharedMethods is owned by some other object.

Keeping a class running in the background when another has been started

I will try and explain this as best as possible if I have this code here
ViewTwoController *home = [[ViewTwoController alloc] initWithNibName:#"contentscreen" bundle:nil];
[self presentModalViewController:home animated:YES];
[home release];
I will start a new .m and .h class. What I would like to try and do however is when this is called, have the .m and .h class where it was called from running in the background so I do not lose data.
The best example I can think of is with Android. If you begin a new class, and don't add the finish() statement in the class the call was made from, the previous class runs behind the current class (that was pushed to the front) and maintains all the data it originally had, so if you hit a return button, you will see the information you had moments ago. Is this possible? I can try add more detail if people cannot understand what I am trying to do.
You need to understand a objects life cycle a little better.
An object is brought into existence generally with a 2 part process.
allocation - (grabbing the memory for the object and its members)
initialization - (setting the object up for use)
This can be combined into single step with the +new class method which combines alloc and init.
lets introduce an example class called MyClass and an object of that class called myObject. By convention classes start with uppercase letters and objects start with lowercase letters. So Without further ado, some code:
MyClass * myObject;
this this makes an object pointer, but doesn't allocate any memory for it or direct the pointer to reference anything.
myObject = [[MyClass alloc] init];
this actually creates an instance of MyClass, passes the -init message to it, then assigns the return value of the init message to myObject. At this point the reference count of this object is 1.
myObject can potentially go out of scope but that alone doesn't free the memory that was allocated during the alloc step.
in order to free that memory a release message will need to be passed to the object.
[myObject release];
The effect of release is to decrement the reference count, if the reference count is already 1 then the object will then be passed the -dealloc indicating that it is actually being freed.
back to your question... essentially [self presentModalViewController:home animated:YES]; ends up calling -retain on home, so that it will not be destroyed until you dismiss the modal view controller. In affect when you call release or autorelease you aren't dealloc'ing the object, just telling the object:
"Hey, I don't need you anymore, and if no one else does either then free up all the memory that you grabbed earlier".
Your problem has nothing to do with "class running in the background" but more with how you manage your data.
When you present a modal view controller, its parent (the view controller you presented it from) isn't destroyed (unless you specifically release it, which would probably crash your app later). So if you're wondering whether its still in memory; it is. As for tasks still running, it depends on what those tasks are. For example, you can still send it messages (call methods) and it will gladly receive those messages from your or from a delegate and perform whatever action it has to while it's off-screen.
Hope that helped.
In this case you are presenting new view controller. The main thread will be in the new controller presented. If you want something to run in background in the previous view controller then you can create a background thread. This can be done using [self perfomselectorInThebackground ... ] Or some other methods like GCD. (The main thing is you should not block Main thread)

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

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.

Core Data - How to check if a managed object's properties have been deallocated?

I've created a program that uses core data and it works beautifully.
I've since attempted to move all my core data methods calls and fetch routines into a class that is self contained. My main program then instantiates that class and makes some basic method calls into that class, and the class then does all the core data stuff behind the scenes. What I'm running into, is that sometimes I'll find that when I grab a managed object from the context, I'll have a valid object, but its properties have been deallocated, and I'll cause a crash. I've played with the zombies and looked for memory leaks, and what I have gathered is it seems that the run loop is probably responsible for deallocating the memory, but I'm not sure.
Is there a way to determine if that memory has been deallocated and force the core data to get it back if I need to access it? My managedObjectContext never gets deallocated, and the fetchedResultsController never does, either.
I thought maybe I needed to use the [managedObjectContext refreshObject:mergeData:] method, or the [managedObjectContext setRetainsRegisteredObjects:] method. Although, I'm under the impression that last one may not be the best bet since it will be more memory intensive (from what I understand).
These errors only popped up when I moved the core data calls into another class file, and they are random when they show up.
Any insight would be appreciated.
-Ryan
Sounds to me like you are not retaining objects you want to keep hanging around. If you are doing something like this:
NSArray *array = [moc executeFetchRequest:request error:&error];
you do not own the returned array and it will most likely disappear when the current autorelease pool is drained. This will occur when the run loop finishes processing the current event.
All this is speculation. If you want a proper answer, you need to post your code.
It's hard to know what the problem is based on your description, but you might want to look at the Core Data memory management guide. You shouldn't have to worry about memory management for managed objects and their entities (they're fetched and faulted automatically). When you talk about "properties," do you mean custom properties backed by ivars? If so, these should be released in didTurnIntoFault and allocd as needed (probably in the accessor).
I was struggling with a similar issue. I'm using a managed object class and want to set its properties dependent on user input. But the sometimes the properties and sometimes the whole managed object were deallocated.
After reading the Apple documentation http://developer.apple.com/library/IOs/#documentation/Cocoa/Conceptual/CoreData/Articles/cdMemory.html the chapter "The Role of the Managed Object Context" I learned that managed objects are released each run loop completes.
And there is the golden advice to set
[myMangedObjectContext setRetainsRegisteredObjects:YES];
(I had to set it in the init method (initWithNibName for me) of my view controller.)
You should also regard to retain only the objects you need to as explained in the documentation. But read it yourself.
If I'm not right please correct me.
I also made a class that handles all my CoreData fetching and stuff. I ran into a couple of gotcha's, so here are some tips. (If I am making any memory management errors in these examples, please let me know.)
Two things:
1) Made a "fetchFiredObject" method in the CoreData handler class. So when I want to get a managedObject that has all its variables and is a "fully feathered bird" so to speak, instead of doing:
aManagedObject *myManagedObject = [myCoreDataHandler.managedObjectStorageArray objectAtIndex:1];
int x = myManagedObject.someVariable.intValue;
instead I do:
aManagedObject *myManagedObject = [myCoreDataHandler fetchFiredObjectAtIndex:1];
int x = myManagedObject.someVariable.intValue;
And in myCoreDataHandler's fetchFiredObjectAtIndex:i method, we're going into the array, finding the object key at index i, then doing a fetchRequest for that object key, and returning the freshly-fetched managedObject so that it won't have been faulted or deallocated, etc. :D
2) When I create a new child viewController, I populate its "myCoreDataHandler" value from the parent upon creation. However, this happens on a subsequent line of code after the line of code that creates the new viewController. Therefore, any code in the child's viewDidLoad that tries to use myCoreDataHandler's methods will return empty objects because viewDidLoad completes before the parent's next line of code where it sets the values of globals in the child object. So make sure you are not accessing your "Core Data handling object" from within viewDidLoad or anything local methods called by viewDidLoad! Instead call them from the parent after creating the new viewController.

Which iPhone OS memory management rules and how-to's do you know?

Currently I am jumping into the ice cold water called "memory management in iPhone OS".
Here's one rule i've learned:
Every time I see an alloc in my method, I will release that corresponding variable at the bottom of the method.
Every time I create an #property(...) in my header file which says copy or retain, I put a release message on that variable into the dealloc method.
Every time I have an IBOutlet, I do the same thing. Only exception: If the IBOutlet has something like #property(... assign), or in other words: If it has the assign keyword at all. Then I don't care about releasing it in the dealloc method.
I feel that there are many more good rules to know! Just write down what you have. Let's scrape them all together. Links to great descriptions are welcome, too.
Actually, any time you initialize an object and the method name includes "init" you are responsible for releasing it. If you create an object using a Class method that does not include the word "init" then you don't.
For example:
NSString *person = [NSString stringWithFormat:"My name is %#", name];
does not need a release. But:
Person *person = [[Person alloc] init];
needs a release (as you stated in your question). Likewise:
Person *person = [[Person alloc] initWithName:#"Matt"]];
also needs a release.
This is a convention, not a rule of the language, but you will find that it is true for all Apple-supplied APIs.
The rules I use
Release all objects you create using a method whose name begins "alloc" or "new" or contains "copy".
Release all objects you retain.
Do not release objects created using a +className convenience constructor. (The class creates it and is responsible for releasing it.)
Do not release objects you receive in other ways E.g.
mySprockets = [widget sprockets];
If you store an object you receive in an instance variable, retain it or copy it. (Unless it's a weak reference - just a pointer to another object, usually to avoid cyclical references.)
Received objects are valid within the method they are received in (generally) and are also valid if passed back to the invoker.
Some good links:
http://www.gehacktes.net/2009/02/iphone-programming-part-2-objective-c-memory-management/
http://mauvilasoftware.com/iphone_software_development/2008/01/iphone-memory-management-a-bri.html
Memory management can seem daunting when you're seeing segfaults spring from every seeming innocent line of code, but it's actually pretty easy once you get the hang of it. Spend a little time reading this page and then Apple's documentation, and you should be writing bug-free code in no time.
I tend to create only autoreleased objects, either by using a class method or by autoreleasing it immediately after creation, unless I can state a reason not to. For example:
I am assigning it to a member variable because I intend to hold onto it for a while.
I am only creating it to pass it on immediately to another method, and I send it a release message right after that method call.
For performance reasons, I need to free that memory before the nearest NSAutoreleasePool will be released, such as creating a large number of objects inside a loop or the objects are holding onto a large amount of data (e.g., images).
That way, I am less likely to leak objects. By default, I create them autoreleased, and when I make the deliberate decision not to autorelease them, I am immediately faced with the question of where they will be released.
For object properties, rather than releasing them in my dealloc method, I like to assign nil to them. That way, retained or copied properties are sent a release, while assigned properties are simply overwritten, and I don't have to update my dealloc method if I change the property to/from retained.