views:

117

answers:

2

Hi everybody. I'm going crazy with this my little app... Please help me!!!

this is the source code of the app: Smoking.zip

It only saves a .dat file with an NSMutableArray. Now, the first time you will launch the app, try to click the cigarette button sometimes: Everything should working fine. Ok, now close the app, re-open it, and click again on the button. This time the app will crash with the "unrecognized selector sent to instance 0x5d18d60" error. I was sure the problem was in saving the data, because when i commented the line "[theData writeToFile:dataFilePath atomically:YES];" in the "saveData" method the error disappeared. Later i discovered that it appears again if i try to read the data from the NSMutableArray.

Please take a moment to check my project and help me, beacause i'm going crazy about that!!

A: 

easy. On SDK 3.2 and 4.0 you need to make your button functions like this.

// Note it takes one argument UIButton.
- (IBAction) smoke:(UIButton * ) button {

Change this in your .h file and .m file, you dont haven to change anything else. Worked for me.

John Ballinger
Thank you but this is not solving my problem... Are you sure it solves for you?
Abramodj
John Ballinger: How does changing the signature of the action methods affect the over-release bug that causes the exception stated in the question? Moreover, the form used in the code is valid in Cocoa Touch applications: http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/CocoaFundamentals/CommunicatingWithObjects/CommunicateWithObjects.html#//apple_ref/doc/uid/TP40002974-CH7-SW44
Peter Hosey
it doesn't I didn't read his questions right. When I ran his code, it crashed on this selector. So after fixing that it ran for me, I assumed this was the issue in his code.
John Ballinger
+1  A: 

You crazy man, it took quite some time to find these lines:

Cig *oldCig = [mainDelegate.smokeArray lastObject];

...

[oldCig release];

Why are you doing that? You effectively reduce the retain count of the last object in the array to 0. When saving, it is happily saved, with its retain count of zero.

On de-serialization, the decoder will retain any (sub) element it decodes, so the retain count of this last object will, for a brief moment, be 1. Then, on release of the decoder, it releases all elements, and poof goes the last Cig object. When getting that object from the array, you get a pointer pointing to something totally different, and the app crashes.

You should read up on memory handling. lastObject just returns a pointer to an object in the array, without retaining it for you, so you don't have to release it. Furthermore, for functions like

- (NSArray *) quando

try to return an autoreleased array, by calling autorelease before returning:

NSArray *newArray = [[[NSArray alloc] initWithObjects:year,...,nil] autorelease];

Then your other code doesn't have to think about releasing it. And release the dateFormatter. Anything you alloc, retain, copy or new, you must release or autorelease!

mvds
More to the point: The array owns its objects, not you. You don't own them, so don't release them. The place to “read up on memory handling” is the Memory Management Programming Guide for Cocoa: http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/MemoryMgmt/
Peter Hosey
The static analyzer picked this one up for me as well as a bunch of leaks. Build and analyze won't always work, but it does find clear breaches of memory management rules like this one. I'd suggest giving it a try.
Ira Cooke
Thank you very much mvds! I really don't know how to thank you... Or maybe i know: i will read up on memory handling! ;-)
Abramodj
@ Ira Cooke: What is "static analyzer"? I would be happy to try it
Abramodj
@ Ira Cooke: Ok, i did a Google search and found out what it is. It's wonderful! It will make my learning of memory management easier. Thanks a lot!
Abramodj