I've made a popup view, with a UIButton on it which closes the view. Whenever I put on the button, the program quits with this message: [MTPopupWindow performSelector:withObject:withObject:]: message sent to deallocated instance 0x84675f0
Here is the header file and source file to use the class I use this line of code:
[MTPopupWindow showWindowWithContent:#"Some text here" insideView:self.view];
I thought that there was something wrong with deallocating my objects too soon but since I'm using ARC I'm not sure what is causing this problem. I think the problem is in this line of code:
[self.closeBtn addTarget:self action:#selector(closePopupWindow) forControlEvents:UIControlEventTouchUpInside];
But I don't see anything wrong with this.
You should have known there was a problem when you wrote this:
// Cast to void because we don't use the result (otherwise compiler warning)
Since you don't use the result, ARC believes that it's free to insert a release on your object after that line, which means the object is getting deallocated way early.
There are a number of ways around this; take a look at things like NS_RETURNS_RETAINED or having the caller of your popup window hold a strong reference to it.
Related
I presume this isn't a common problem, which makes it a bit more difficult to answer. Any help is appreciated though.
I need to call this delegate a number of times in my app, and i noticed that after a number of times, the delegate starts to come back as NULL (and hence stops responding). I put an nslog everywhere the delegate gets called, so i know that at this point, it's fine:
UIImage *image = [self.delegate largeThumnailForMediaAtIndex:indexPath.row];
Then the next time this line gets called, the delegate is set to NULL. No lines around it call or set the delegate. I put an NSLog on the setDelegate method too, and that didn't get called before it changed to NULL.
Any code you might need to see, let me know. Any ideas you want me to try out, let me know about that too.
Thanks for your help.
EDIT: Bizarre, but might help to lead to a solution. I put an NSTimer scheduledTimer.. in the class which gets made the delegate, and got it to fire that once a second so I could see if it turned null at any point. The result i got, however, was that this time it didn't turn null. It returned all of the delegate methods. When i took the timer out, it goes back to returning NULL. Obviously having a timer in there is an odd workaround 'solution'. I'm hoping this rings a bell for someone and gives them a clue to where the problem might lie?
EDIT 2: I've solved this problem by, instead of using this code in my AppDelegate:
JCreateViewController *create = [[JCreateViewController alloc] init];
[create.navigationBar addLeftButtonWithTitle:#"Back" type:JButtonTypeArrow];
create.navigationBar.title = #"Entry #17";
[self.window addSubview:create.view];
Declaring it in my header file, then using this:
self.create = [[JCreateViewController alloc] init];
[self.create.navigationBar addLeftButtonWithTitle:#"Back" type:JButtonTypeArrow];
self.create.navigationBar.title = #"Entry #17";
[self.window addSubview:self.create.view];
I don't understand why this makes a difference though. I'd love to know, if anybody does know?
Looks like you're using ARC. Whatever this object is, nothing owns it. Nothing has a strong reference to it, so it gets released, and then at some point it gets deallocated.
JCreateViewController *create = [[JCreateViewController alloc] init];
This is a local variable. When the variable goes out of scope at the end of the method, you can't access that object anymore. Under MRR, this would be a leak. Under ARC, the object is going to die, just like it was in an autorelease pool.
self.create = [[JCreateViewController alloc] init];
By creating a property (presumably strong) and putting the controller into that property, you've given whatever self is an owning reference to the controller. It will now live as long as the property isn't reassigned or set to nil.
The timer fixed things because the timer retains its target (which I believe was the controller (your question is rather unclear)), and the timer itself is retained by the run loop. So the run loop keeps the repeating timer alive and the timer kept your controller alive.
In short, make sure something owns this object and it'll stick around.
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!!
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!
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.
I Have the following code:
-(void) changeAnimation:(NSString*)name forTime:(int) times {
if(currentAnimation != #"attack")
{
id action = [CCAnimate actionWithAnimation:[self animationByName:name]];
id repeatAction = [CCRepeat actionWithAction:action times:times];
currentAction = [self runAction:repeatAction];
lastANimation = currentAnimation;
currentAnimation = name;
}
else if(currentAction.isDone)
{
//Here is where I would change the animation
//but I commented the code for now
}
}
So when I run this and click on the button that changes the animation to "attack" (by calling [mysprite changeAnimation:#"attack" forTime:1];), I get a EXC_BAD_ACCESS error from the "currentAction.isDone" line, the next time the function is called (the joystick will call changeAnimation to try and change the animation to "run" or "idle", but I want the attack animation to finish first). Any thoughts on whyI get this? currentAction is declared in my class.
Edit: there is nothing in the rest of the class that interacts with currentAction, beside a getter. Its declaration is in the .h (CCAction* surrentAction). Do I need to initialize it? I thought the returned value from runAction would be sufficient? ANyways, when I run the debugger, it is not nil, and assigned to the correct action.
Thanks,
Dave
Edit:
I ended up creating a sequence when "attacking" that calls a function that changes the currentAnimation, so i avoided the issue. Still no idea what was happening.
Here's the answer if your interested:
Other Post
More of the class is probably needed to really answer this properly, but the EXC_BAD_ACCESS typically happens because you're accessing something that has been released and is no longer available in memory.
I'm guessing that somewhere in your class you're releasing, either explicitly, or implicitly, the "currentAction" object asynchronously - and when you're checking later, it's done & gone and you're hitting this crasher.
In general, keeping a state variable or two that you always have known values on is a good way to go, and for the "actions" that you're going through, if they're asynchronous and doing their own memory management, leave them as such and work through some state variables that you maintain and control all the memory management around. It's a pretty reasonable pattern for asynchronous callbacks, either with the classic stuff or as you move into using blocks with iOS 4.0
I'm very new to cocoa touch and am stuck on a problem that doesn't seem to have a google solution. I have added a view to my application, and this view has a button on it. When the button is pressed I want the callback to perform an operation.
My problem is that the callback isn't being called. I created the view in Interface Builder, connected the touch-up-inside connection to my Owner class (in this case a viewController class), and selected the appropriate callback.
The error I get is as follows:
2009-10-13 17:13:51.708 MyApp[7467:20b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSCFSet contactsButtonPressed:]: unrecognized selector sent to instance 0x4c27330'
As I understand it this suggests that the connection between contactsButtonPressed and MyViewController is wrong. I'm not sure where the NSCFSet object comes from.
Does anyone have any idea?
Thanks!
The error I get is as follows:
2009-10-13 17:13:51.708 MyApp[7467:20b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSCFSet contactsButtonPressed:]: unrecognized selector sent to instance 0x4c27330'
You're probably under-retaining whatever controller object of yours is supposed to receive that action message. Add an NSLog call in the controller's dealloc method; you'll probably find that it gets deallocked before you expect it to.
The question to ask then is what should own that controller. Then, make sure that all of the owners are retaining it.
If you're holding the controller in a property, make sure that you actually use that property. A common mistake is to write myController = theController, which bypasses the property and assigns directly to the instance variable, instead of self.myController = theController (property access syntax, implicit accessor message) or [self setMyController:theController] (explicit message syntax).
Also, if you've implemented your own accessors for the property (especially setMyController:), make sure your setter releases the old object and retains the new one. Of course, this is assuming you have a reason to implement your own accessor; normally, you should simply #synthesize the property and let the compiler write the accessor for you.
somewhere in your code you have a line that looks like this:
[button addTarget:self action:#selector(contactsButtonPressed:)];
If you have a line that looks like this, you will also need to have a method with this signature:
- (void)contactsButtonPressed:(UIButton *)sender {
...
}
If you look at the error, it seems that you are sending the message to an NSCFSet object instead of the controller. I would check that you are setting delegate to self or the controller.
I'm new to cocoa too,
Maybe you forgot to add the sender parameter to your contactsButtonPressed.
Is your view's class named NSCFSet?
Try pasting some code.
I appear to have some overzealous releasing going on in my obj-C app - getting error message
"-[myobj release]: message sent to deallocated instance 0x5633b0"
. I know the class of the object instance causing the problem, but this class is used all over to create many instances.
My thought is I could put some logging in the init method of the class to log whatever "0x5633b0" corresponds to which should help me track down where the instance is being created.
What exactly is the "0x5633b0" and is there any way I can get access to that value in the code to log it?
Thanks.
What worked best for me when I ran into similar problems recently was the following:
Under under Project->Edit Active Executable -> Arguments tab -> Environment variables section I added and set to YES the following variables: NSAutoreleaseFreedObjectCheckEnabled, NSZombieEnabled and NSDebugEnabled.
Under the Run menu, I selected Enable Guard Malloc.
With these settings the debugger provided more hints on what's wrong with my code.
(I found these tips here)
Good luck,
Ori
0x5633b0 is likely the address of object in question (the value of self). You can use NSLog or printf with %p to print it.
0x5633b0 is likely the address of the deallocated object (the value of myobj). You can use NSLog or printf with %p to print it.
You can also use the instruments profiler to find the deallocated object.
1. Start the profiler:
2. Select the "Zombies" and start the profiler.
3. Click through the simulator until you hit your "deallocated error case"
In the debugger, type info symbol 0x5633b0 and you'll get some indication as to what object it is. One other thing that might be helpful is backtrace which will give you a stack trace. All in all, this blog entry has some great tips.
you can also add these to environment variables:
MallocStackLoggingNoCompact 1
and write in the gdb console:
info malloc-history <paste-address-here>
Reference: here
Consider using the NSZombieEnabled flag.
You will then know what is this deallocated object you're sending a message.
You're not managing your memory properly -- you're calling release/autorelease on some object more times than you're calling retain. Make sure you're following all of the rules laid out in the Memory Management Programming Guide for Cocoa.
0x5633b0 is just the address of the memory location at which the object is stored. One thing you can try to do is to add some code to the init method:
- (void) init
{
if(self == (MyClass*)0x5633b0)
NSLog(#"Allocated object at address 0x5633b0"); // put a breakpoint on this line
// do rest of init...
}
If you have any other init methods (e.g. initWithCoder:, which is called for objects instantiated from a XIB), make sure to put this snippet in those methods as well. Put a breakpoint on the NSLog line, and then see when it gets hit. Note that it may get hit several times, if an object is allocated at that address, deallocated, and then another object happens to be reallocated at the same address. The last hit before the crash is the one you want.