Object alloc init irregularities - objective-c

I'm seeing some disturbing irregularities concerning object allocation and initialization in an app I'm trying to write.
I have a 'root' Modelcontroller object, which in turn contains references to subcontrollers. The root controller is called modelController, and in it's init method it allocates and inits the subcontrollers like so:
- (id)init
{
NSLog(#"%#", #"ModelController begin init");
self = [super init];
if (self) {
LibraryController * tempLibrary = [[LibraryController alloc] init];
self.library = tempLibrary;
StoresController * tempStores = [[StoresController alloc] init];
self.stores = tempStores;
CLLocationManager * tempLocationManager = [[CLLocationManager alloc] init];
self.locationManager = tempLocationManager;
}
NSLog(#"%#", #"ModelController complete init");
return self;
}
Pretty standard. The subcontrollers' init code also contain an NSLog messages at the beginning and the end, for me to be able to see that all is well.
The properties are defined as
#property (strong) LibraryController * library;
#property (strong) StoresController * stores;
#property (strong) CLLocationManager * locationManager;
And I am using ARC.
What puzzles me is that sometimes I see the NSLogs from one of the subcontrollers, but not from the root controller. Sometimes I see the 'begin init' log message from the root controller, but not the 'complete init'. Sometimes I see no init log messages. The application launches anyway in any of these cases.
This happens seemingly at random, in one out of five launches or in one out of twenty launches. When it happens, the app acts very strange (but not every time, mind you), beachballing for no apparent reason and exhibiting general wonkiness.
As a side note, at one time I put a breakpoint in the init method of the StoreController class, which when pausing executing spit out a chunk of random data in the debugging console:
$m2303,3503,3603,3703,3803,3903#00$m2303,3503,3603,3a03#00$88ee410901000000981e420901000000001e42090100000060ee410901000000b062f668ff7f000070044391ff7f0000f00e0800000000000300000068200100dc62f668ff7f0000d862f668ff7f00000000000000000000717ddd8aff7f00000000000068200100801e420901000000000000000600000706000007000000007063f668ff7f000003280000000000007863f668ff7f000001ee410901000000f062f668ff7f00006c5bd391ff7f000000000000ff7f0000ab064391ff7f000000000000ffffffff032800000000000040
...and so on
Where should I begin to look to troubleshoot this?
The modelController is alloc init'd from the MyDocument equivalent class, and is modeled as a singleton.
The singleton implementation looks like this:
static ModelController *sharedModelController = nil;
+ (ModelController*)sharedManager
{
if (sharedModelController == nil) {
sharedModelController = [self new];
}
return sharedModelController;
}
Final note: I have tried removing the locationManager stuff and disabling/enabling the 'Restore state' preference in the scheme, but to no avail.

Sounds like you're doing some UI stuff not on the main thread.
This generally leads to weird behavior.
Make sure you call everything UI related on the main thread

Best guess: the ModelController object is being released. Perhaps the Singleton is faulty.

Related

NSImage memory leak

First of all: I already searched on google and SO for solutions - none worked.
I've got an application which loads the artwork of the current iTunes track and displays it; this is stored in a NSImage instance, among some other variables, in a class:
#interface infoBundle : NSObject
#property (strong) NSImage *track_artwork;
#property (weak) NSString *track_title;
#property (weak) NSString *track_album;
#property (weak) NSString *track_artist;
#end
Then, an instance of this class is created:
-(infoBundle*)returnInfoBundle {
infoBundle* tmpBundle = [[infoBundle alloc]init];
tmpBundle.track_artwork = [[NSImage alloc]initWithData:[(iTunesArtwork *)[[[iTunes currentTrack] artworks] objectAtIndex:0] rawData]];
[...]
return tmpBundle;
}
And later used:
-(void)iTunesDidChange {
infoBundle* tmpBundle = [self returnInfoBundle];
[...]
[imageView setImage:tmpBundle.track_artwork];
}
That's eating up ~2MB (Cover size, I'd guess) per call of iTunesDidChange.
I already tried:
[tmpBundle autorelease];
[tmpBundle release];
[tmpBundle dealloc];
tmpBundle = nil;
and, after that didn't help:
- Enabling ARC.
=> Why is this eating up memory, although the object (tmpbundle) should get removed?
=> How may I achieve leak-less NSImage usage?
Thanks for any tips/suggestions/solutions :)
Issue
You will have a memory leak if you create your object on your method and not release it inside that method or you have to reference it when you pass it as a parameter by reference : Passing arguments by value or by reference in objective C
Your problem is that you are creating an instance of infoBundle two times, and when you are initializing another instance of it, you are leaving the first one without reference, so it remains in memory, and without connection to remove it (memory leak).
Solution
To make your things easier you should create an instance of your object
#implementation
{
infoBundle* tmpBundle;
}
Use it where ever you need it
-(infoBundle*)returnInfoBundle
{
tmpBundle = [[infoBundle alloc]init];
tmpBundle.track_artwork = [[NSImage alloc]initWithData:[(iTunesArtwork *)[[[iTunes currentTrack] artworks] objectAtIndex:0] rawData]];
[...]
return tmpBundle;
}
-(void)iTunesDidChange
{
tmpBundle = [self returnInfoBundle];
[...]
[imageView setImage:tmpBundle.track_artwork];
}
And when you are finished with that object dealloc will automatically release it if you add it to dealloc method:
- (void) dealloc
{
[tmpBundle release];
tmpBundle = nil;
}
Hope it helps! :)
Just modifiy this line :-
infoBundle* tmpBundle = [[[infoBundle alloc]init]autorelease];
I can’t tell from your code what you are doing in [imageView setImage:tmpbundle.track_artwork]; but you may be having the same problem I had.
I was using
self.imageToDisplay = [UIImage imageNamed:pictFileName];
and kept getting leaks. I switched to
self.imageToDisplay = [UIImage imageWithContentsOfFile:pictFile];
and they went away.
According to the documentation for imageNamed,
This method looks in the system caches for an image object with the
specified name and returns that object if it exists… If you have an
image file that will only be displayed once and wish to ensure that it
does not get added to the system’s cache, you should instead create
your image using imageWithContentsOfFile:. This will keep your
single-use image out of the system image cache, potentially improving
the memory use characteristics of your app.
It sounds like you have either the same or a similar issue.

NSMutableDictionary Singleton issue

I am coding Objective-C using the Cocos2D framework, and I have a singleton used for multiple purposes. One new purposes is to get and set character's "states" which are strings. I've recently made an NSDictionary for this purpose, but I have issues with the program freezing up when a method inside the singleton is called.
Here's the singleton code. I'm just leaving in the character state stuff:
.h
#interface ExGlobal : NSObject {
NSArray *charStates_keys;
NSArray *charStates_objects;
NSMutableDictionary *charStates;
}
#property(nonatomic, retain) NSMutableDictionary *charStates;
+(ExGlobal*)sharedSingleton;
- (NSString *)charState:(NSString *)charName;
- (void)set_charState:(NSString *)value forCharName:(NSString *)charName;
#end
.m
#import "ExGlobal.h"
#implementation ExGlobal
#synthesize charStates;
static ExGlobal* _sharedSingleton = nil;
+(ExGlobal*)sharedSingleton {
#synchronized([ExGlobal class]) {
if (!_sharedSingleton) {
[[self alloc] init];
}
return _sharedSingleton;
}
return nil;
}
+(id)alloc {
#synchronized([ExGlobal class]) {
NSAssert(_sharedSingleton == nil, #"Attempted to allocate a second instance of a singleton.");
_sharedSingleton = [super alloc];
return _sharedSingleton;
}
return nil;
}
-(id)init {
self = [super init];
if (self != nil) {
// initialize stuff here
exitName = #"ruinsSkyMid";
sceneChangeKind = #"reborn";
charStates = [[NSMutableDictionary alloc] init];
charStates_keys = [NSArray arrayWithObjects:#"Feathers", #"Hummus", nil];
charStates_objects = [NSArray arrayWithObjects:#"at wall", #"with Feathers", nil];
charStates = [NSMutableDictionary dictionaryWithObjects:charStates_objects forKeys:charStates_keys];
}
return self;
}
- (NSString *)charState:(NSString *)charName{
NSString *value = [charStates objectForKey:charName];
return value;
}
- (void)set_charState:(NSString *)charState forCharName:(NSString *)charName{
[charStates setObject:charState forKey:charName];
}
- (void)dealloc {
//I know it doesn't get called, but just in case
[charStates release];
[super dealloc];
}
#end
It's unclear to me what exactly the issue is when it freezes. When this happens, all I get in the console is:
Program received signal: “EXC_BAD_ACCESS”.
warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3.5 (8L1)/Symbols/Developer/usr/lib/libXcodeDebuggerSupport.dylib (file not found).
Previous frame inner to this frame (gdb could not unwind past this frame)
Previous frame inner to this frame (gdb could not unwind past this frame)
Which I'm sure doesn't help finding the issue. I found if I redefine charStates_keys, charStates_objects and charStates inside both the charState and set_charState methods, it seems to work without freezing, except set_charState does not change the state.
It isn't freezing, it is crashing. Hence the EXC_BAD_ACCESS. It looks like your Xcode installation is borked, too, as the two messages following should not happen.
Note that methods should not have _s in the name; not a cause of the problem, but a comment on following convention.
You aren't retaining charStates and that is likely the cause of the crash.
Not an answer as such but I didn't have enough space in the comments field above to post this, but it might be useful.
As bbum already said, your lack of retaining charStates is likely the problem.
If you are confused about when to retain and not retain objects there's a really good book called "Learn Objective-C on the Mac" and I know it's a Mac book but most of it applies to iPhone too. On page 171 of chapter 9 (Memory Management) it talks about the "Memory Management Rules" and how if you are confused about when to retain or not then you don't understand the simple rules of Objective C memory management.
Essentially if you create an object using new, alloc or copy, then the retain count is automatically set to 1 so the object is retained and does not require you to retain it and will require a subsequent release to deallocate.
If you create the object any other way then the object will be an autoreleased object.
Obviously these rules only apply within the standard iOS libraries and can't necessarily be applied to third party libraries.
I recommend anyone who doesn't fully understand memory management in Objective C read this book. I found highly enlightening even for my iPhone work.
Hope that helps/.

Leaks reports seemingly unrelated issues

I'm fairly new to Cocoa and Objective-C. Currently I'm developing a fairly basic application to test my knowledge and put some of the stuff I've been reading about into practice. Everything is working, but Leaks reports a number of issues.
None of these leaks seems to be directly applicable to code that I've written (I have read and tried to follow Apple's rules on memory allocation). Currently my project makes use of Garbage Collection and I'm developing on Snow Leopard. Running AnalysisTool finds no issues with my code (aside from a few naming convention warnings).
Currently my application makes use of an NSTableView which I have hooked up to an NSArrayController. Interacting with the NSTableView seems to cause leaks to report issues (actions such as sorting table columns and other standard user interaction). This leads me to believe that my use of the NSArrayController (and my implementation of its content source) is to blame.
Currently the NSArrayController receives its content from an NSMutableArray (timers) handled in my Application's delegate like so:
- (id) init
{
if (self = [super init])
{
timers = [NSMutableArray array];
}
return self;
}
- (void) dealloc
{
[timers release];
[super dealloc];
}
Within Interface Builder my NSArrayController has its Object Controller set to the Timing class, which is defined below:
#interface Timing : NSObject {
NSString *desc;
NSDate *timestamp;
bool active;
}
#end
#implementation Timing
-(id) init
{
if (self = [super init])
{
desc = #"New timing";
timestamp = [[NSDate alloc] init];
active = false;
}
return self;
}
-(void) dealloc
{
[timestamp release];
[super dealloc];
}
#end
I've used standard Cocoa bindings to hook up Add and Remove buttons to manipulate the TableView and these seem to work correctly (clicking Add will create a row in the TableView with the value of 'New timing', for instance).
Leaks reports that the libraries responsible are AppKit and CoreGraphics. Although, honestly, I'm still new to the Leaks tool - so I could be reading its output incorrectly. If it helps, I've placed a screenshot of its output here. If anyone could point me in the right direction, that would really be appreciated.
As an aside, I've also been experimenting with manually adding objects to the timers array without the use of Cocoa bindings. Here's what I came up with:
Timing *timingInstance = [[Timing alloc] init];
[timers addObject:timingInstance];
[timingInstance release];
[timersController setContent:timers];
[timersTableView reloadData];
Again, this seems to work, but I thought it best to ask the experts!
Your memory management for the timers array is not quite correct. Using the array factory method will return an instance of NSMutableArray that has already been autoreleased, so the lifetime of that object is (probably) limited to the end of the current run loop, and it will be over-released when you call release in your dealloc method. The proper way to do it is as follows:
- (id) init
{
if (self = [super init])
{
timers = [[NSMutableArray alloc] initWithCapacity:0];
}
return self;
}
This method will give you an instance of NSMutableArray with a retain count of 1, which will then drop to zero (and properly release the memory) when you call release in your dealloc method. The call to alloc in your init method is balanced out by the call to release in your dealloc method. I notice that this is the exact pattern that you used for your NSDate object in the Timing class, so you are already familiar with the idea.
Your code as written is not leaking. The Cocoa frameworks will sometimes generate false leak reports when run under leaks, as certain things such as singletons and caches which are used in the implementation of the frameworks will sometimes show up as leaks even though they're not.
You're probably better off running the ObjectAlloc and/or ObjectGraph instruments to get an idea of when your objects are being allocated and deallocated.
Currently my project makes use of
Garbage Collection and I'm developing
on Snow Leopard
I don't understand. You're using garbage collection right? If so then GC takes care of releasing objects for you so anywhere you use "release" does absolutely nothing. Release calls are ignored when GC is enabled. You only use release when you're managing the memory yourself which is when GC is off. Also, your dealloc methods do nothing too. In GC that method is never used. When you create an object and then you finish with it you tell GC that it's OK to get rid of the object by setting it to nil. That's all you have to do. There is no "release" needed or dealloc method needed. Just set things to nil or or not as needed.

When is an autoreleased object actually released?

I am new in objective-c and I am trying to understand memory management to get it right.
After reading the excellent
Memory Management Programming Guide for Cocoa by apple my only concern is when
actually an autoreleased object is released in an iphone/ipod application. My understanding is at the end of a run loop. But what defines a run loop in the application?
So I was wondering whether the following piece of code is right. Assume an object
#implementation Test
- (NSString *) functionA {
NSString *stringA;
stringA = [[[NSString alloc] initWithString:#"Hello"] autorelease]
return stringA;
}
- (NSString *) functionB {
NSString *stringB;
stringB = [self functionA];
return stringB;
}
- (NSString *) functionC {
NSString *stringC;
stringC = [self functionB];
return stringC;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSString* p = [self functionC];
NSLog(#"string is %#",p);
}
#end
Is this code valid?
From the apple text I understand that the NSString returned from functionA is valid in the scope of functionB. I am not sure whether it is valid in functionC and in viewDidLoad.
Thanks!
Yes, your functions are valid, and return objects using correct Cocoa conventions for retain/release/autorelease/copy.
To answer your question about what the runloop is, in your application's main() function, it invokes UIApplicationMain(). You can imagine UIApplicationMain looks something like this:
void int UIApplicationMain (int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName) {
UIApplication *app = /* create app using principalClassName */;
[app setDelegate:/* create delegate using delegateClassName */];
while (![app shouldTerminate]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
event = [app getNextEvent];
[app dispatchEvent:event];
[pool drain];
}
}
That while loops is similar to what the UIKit is actually doing, and each trip through that while loop is like a trip through the runloop, where the function getNextEvent blocks waiting for some event to happen. All of your methods are typically called from within something like dispatchEvent:. You might try setting a break point in one of your methods, like an IBAction, and looking in the debugger call stack way up at the top to see the names of the UIKit methods that handle the events and runloop. Since each of your methods are called from within that while loop, each time you call autorelease on an object, that object is added to that outter pool in the run loop. When the current event is finished being dispatched, the pool is drained, and those objects are finally sent release messages.
One last note. There can be more than one autorelease pool, that aren't always at the end of the event loop. Sometimes you might allocate tens of thousands of objects in one trip thorough the event loop. When that happens, you might setup additional inner auto release pools in your own methods to keep the number of autoreleased objects in autorelease pools down. Auto release pools can stack.
There's nothing wrong with that code. It will compile and run as you expect.
The NSString object returned from functionA is still valid upon return since it's being passed down the stack to the next guy (functionB) who is now keeping track of it.

Cocoa without Interface Builder, initialize an instance of app controller?

I don't plan to write applications without IB, I'm just in the process of trying to learn more about programming.
How can I get a single instance of my AppController class at startup? (It's normally loaded from the nib.) And can you clear up the use of +initialize and -init? If I understand, +initialize is called on all classes at startup. How can I use this to create an instance of my AppController with instance variables that make up my interface?
Hope that makes sense, and thanks for any help.
+initalize is sent to a class the first time it or one of its subclasses receives a message for the first time. So, when you do:
instance = [[[YourClass alloc] init] autorelease];
That alloc message triggers initialize.
If you do the same thing with a subclass:
instance = [[[SubclassOfYourClass alloc] init] autorelease];
That alloc message will trigger +[YourClass initialize] the same way the other one did (prior to also triggering +[SubclassOfYourClass initialize]. But only one of these will do it—each class's initialize never gets called more than once. (Unless you call it yourself with [super initialize] or [SomeClass initialize]—so don't do that, because the method won't be expecting it.)
-init, on the other hand, initializes a new instance. In the expression [[YourClass alloc] init], you are personally sending the message directly to the instance. You may also call it indirectly, through another initializer ([[YourClass alloc] initWithSomethingElse:bar]) or a convenience factory ([YourClass instance]).
Unlike initialize, you should always send init (or another initializer, if appropriate) to your superclass. Most init methods look roughly like this:
- (id) init {
if ((self = [super init])) {
framistan = [[Framistan alloc] init];
}
return self;
}
Details differ (this method or the superclass's or both may take arguments, and some people prefer self = [super init] on its own line, and Wil Shipley doesn't assign to self at all), but the basic idea is the same: call [super init[WithSomething:…]], make sure it didn't return nil, set up the instance if it didn't, and return whatever the superclass returned.
This implies that you can return nil from init, and indeed you can. If you do this, you should [self release], so that you don't leak the failed object. (For detecting invalid argument values, an alternative is NSParameterAssert, which throws an exception if the assertion fails. The relative merits of each are beyond the scope of this question.)
How can I use this to create an instance of my AppController with instance variables that make up my interface?
The best way is to do it all in main:
int main(int argc, char **argv) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
AppController *controller = [[[AppController alloc] init] autorelease];
[[NSApplication sharedApplication] setDelegate:controller]; //Assuming you want it as your app delegate, which is likely
int status = NSApplicationMain(argc, argv);
[pool drain];
return status;
}
You'll do any other set-up in your application delegate methods in AppController.
You already know this, but for anyone else who reads this: Nibs are your friend. Interface Builder is your friend. Don't fight the framework—work with it, and build your interface graphically, and your application will be better for it.
Another solution to the problem of launching an app without a nib.
Instead of allocing your own controller, just use the extra parameters in the NSApplicationMain() method:
int retVal = NSApplicationMain(argc, argv, #"UIApplication", #"MyAppDelegate");
This takes care of all the proper linking one would need.
Then, the only other thing you'd need to remember is to make your own window and set it to visible.
A set of NIBs seem to be an unsatisfactory answer, even when represented in XML (as a XIB), because there's no easy way to compare or merge them with any standard subversion or SCM-style tool. The encoded information is fragile and not intended to be edited by mere humans. How would changes be represented by a GUI? Would I step through each attribute of each control and visually check them?
If the app's behavior is written in code, however, there is a chance that I can figure out what's going in, even if I have to keep lots of details close at hand at the same time.
A proposed solution: use a top-level NIB that the main architect coded up, but then code the rest of the app explicitly.
Anybody got a better idea?