Can't understand what is wrong, get EXC_BAD_ACCESS, any hints? - objective-c

I'm having this sprite with this in it's init method
lineDrawer = [[LineDrawer alloc]initWithLineColor:ccc3(color.r, color.g, color.b)];
lineDrawer.position = ccp(0,0);
lineDrawer.anchorPoint = ccp(1,1);
[self addChild:lineDrawer];
[self addChild:head];
[lineDrawer release];
Nothing wrong here right? I can release it as addchild is retaining the object.
(autorelease would also be ok)
Although when I have the release I get EXC_BAD_ACCESS(code=1) later on. I've also tried to move the release to the dealloc method but it gives me the same error.
The only object that has reference to lineDrawer is the spriteobject (Player : CCSprite) it's defined in and It doesn't have a getter so it cant even be accessed by another object, so I don't see how this can happen. What can be calling lineDrawer at the time It's dealloced when only the owner has a reference to it?
It happens on the line CC_NODE_DRAW_SETUP() inside the draw method of CCLayer.
Any hints? I know these questions is always hard to solve with the lack of code but It's really hard to know what code to show you. If I knew I could probably solve it by myself. I've also tried to debug this some in instruments but I'm not sure where to look.
Update,
I tried debugging with zombies enabled
Does this say anything to you?
This is the LineDrawer class. It's someone else's class that I've slightly modified.
http://pastebin.com/7Uv4GULy
http://pastebin.com/08NHeVt9
I have a feeling that its some method that's scheduled or something..

Since you add the lineDrawer object to the child collection of your CCSprite, a public reference to it is available through the .children property defined in CCNode.
However, nothing in the code you've posted seems wrong, except that LineDrawer inherits from CCLayer and I don't think that CCLayer was ever designed to be used as a child of a CCSprite ... does it really need to be a child of your Player object? (e.g. should it be following your Player sprite as it moves and rotates?) Typically a layer is a child of your active CCScene node, or another layer.

Most of these problems don't happen anymore when you are using ARC.
Most likely you have over-released an object. It doesn't necessarily need to be the lineDrawer. Perhaps it's an object inside the lineDrawer class.
Best way to figure this out is to enable NSZombieObjects in the build scheme and find out which object was accessed.

Related

Confusion with Passing Obj-C objects into methods and retaining the changes to that object

I'm writing a program and trying to learn more about threads, multiprocessing, and such.
My architecture is a Model/View/Controller type.
I have my own subclass of NSImageView (ThumbnailView) and I wanted to be clever and have it listen for a message to clear itself (so all the thumbnails just clear themselves without me having to loop through them).
The problem is my ThumbnailView is controlled by a ThumbnailViewController which is really the one listening for the message. When it gets the message it spins off a new thread with a class object that is the command (ClearThumbnailViewCommand). It passes as an argument a dictionary item containing the associated ThumbnailView object and a key. Within the ClearThumbnailViewCommand I set the image of the ThumbnailView object to be some neutral image (like gray.jpg).
All this works fine, however, the Thumbnail object that changed is not the same Thumbnail object that went in. So I figure I need to pass a pointer rather than the object. I remember something about using MyObject** as opposed to MyObject* and passing via &MyObject but I can't seem to untangle the various combinations. Not being able to reason it out I fell back to my, normally, foolproof system of trying random combinations of things but this time it's not helping.
It seems that even if I'm able to construct a class that passes a pointer (Not sure if I'm using these terms correctly), I'm not able to assign it correctly to the NSDictionary, which doesn't want an id** .
I'll try and include the basics below, if that helps at all.
ThumbnailVew : NSImageView {
ThumbnailVewController * _controller;
}
init {
_controller = [[ControllerClass alloc] initWithControlObject: &self];
}
ThumbnailVewController : ControllerClass {
id ** _controlObject;
}
initWithControlObject: (id**)object {
_controlObject = object;
}
Then when messages are posted a ThumbnailVewController method is called which ultimately does this…
Which, of course will not let me pass in &_controlObject
when it is all re-written so that I can pass _controlObject, I don't get an error, however the ThumbnailView I change is only local to the method.
if([command isEqualToString:#"CLEAR_THUMBNAILS"]) {
NSDictionary * dict;
dict = [[NSDictionary alloc] initWithObjectsAndKeys: &_controlObject, #"thumbnail", nil];
[self newThreadWithCommand:[[[ClearThumbnailViewCommand alloc] initWithArgument:dict] autorelease]];
}
Is this even possible?
Thanks for the feedback. I am indeed just trying to explore some various situations. I understand I may be going a round about way to get at some things but it does help me understand the boundaries more clearly.
In case it might help anyone else, I found a solution to my particular issue. As it turns out I was making the reference to the _controlObject in the init phase of the ThumbnailView. The object created during that phase is different than the ThumbnailView object created when awakeFromNib is called.
when I move the _controlObject assignment to the awakeFromNib method all works as I expected. (Of course I reset the code to not include any of the fancy ** and & declarations.
Again, thank you for helping me understand a bit more about this language. I'm starting to like it quite a bit.

dealloc is being called and I am not sure why

I have a view with some buttons, text fields, and methods. When I load the view, switch to another view, and then switch back, my app crashes. I added in an NSLog in each method to see what the last method call before the crash was, and it was -(void)dealloc{
I am wondering why this method was called? Is it called every time you reload a view? I've double checked my code and I definitely do not call it anywhere.
EDIT : Found my problem, I was releasing an array that I was using to store views. Thanks to #Darren I traced my problem.
Dealloc is called when a class is no longer needed and removed from memory.
When you have no more pointers holding onto anything in the view, then it's dealocated.
How are you switching to/from the view?
if you set a (strong) pointer to the view then it won't be dealocated automatically.
-dealloc is called whenever an object's reference count drops to 0. To find your problem, figure out what object's -dealloc was called. What's the second method on the call stack? The third? Was -dealloc sent to a valid object pointer in the first place?
There are several ways to approach this sort of thing. A good first step is to turn on NSZombies (Google for it). That'll let you know if you're sending a message (like, say, dealloc) to an invalid object. Usually, that causes a crash, but with NSZombies you'll get a nice error message instead.

Connecting actions works. Connecting outlets doesn't

I have a XIB file with my controls in it, loaded in the Interface Builder (Xcode 4.0.2 on Snow Leopard).
The file's owner is set to, let's say, the someClassController class, and I've also added (in the Interface Builder) an NSObject instance of someClass, as well.
I've managed to link e.g. a button with an action in someClassController or someClass - and it works for both of them.
However, whenever I link an outlet to ANY of them, it fails to show up; and NSLog reports NULL pointers.
Hint : My issue here could be much more complicated than it seems, since both my someClass and someClassController classes inherit other classes, which inherit other classes and so on (I'm dealing with a huge-to-chaotic codebase, and I don't really know what else could be helpful to post)... However, I would still like to hear your opinion on what might be going wrong in such a case...
When you see problems like this, it's almost always because you have more than one object of the kind that has the outlet. The one in the nib whose outlet you connected is not the one that is examining its outlet.
To investigate this, add statements in the object's initializer method(s) and possibly awakeFromNib to log the value of self.
Some (or all, or none) of the objects may be created in nibs, and some (or all, or none) of them may be created in code; objects in the latter group won't trip awakeFromNib, since they didn't.
Either way, once you've inventoried what instances of the class you have, you can kill them off until you're left with the ones you want.
To add to Peter Hosey's answer, and after reading some more details in the other question you posted about this issue, here are some other factors to consider:
The File Owner class selected in the nib is completely ignored at runtime. It's there only for design-time convenience – for checking available actions and outlets.
Is there any chance you're finding nil pointers in -init? Outlets are connected after -init and before -awakeFromNib. They'll never be connected in -init.
I'm trying to understand the sequence of initialization (from your other post). It sounds like you are creating a new instance of your CTTabContents subclass, and passing it to your CTBrowserWindowController subclass's -addTabContents: method. Then the CTBrowserWindowController loads your objects from the nib.
Or, maybe that's wrong. You might be creating a instance of your CTTabContentsController subclass. Then that object is loading TabContents.xib.
It's important to track down where the nib is being loaded and which object is being provided as the file owner at that time.
Another question: are you using manual release/retain, automatic reference counting, or garbage collection?
Finally, I reiterate the importance of printing out the self pointer in your initialization methods. In addition to -init and -awakeFromNib, try other initialization methods like your CTTabContents subclass' -initWithFrame:. When you're discovering intermittent null pointers in the rest of your debugging, print out the self pointers then, too. You'll probably be seeing different values of self then, too.

How do I initialize a variable instance which is an object properly?

I am an Objective C newbie and I'm sure this is an easy question but I can't figure this out:
I have a class which declares an instance variable called myDeck, which is part of a custom class I created called Deck. Right now I have this in my code:
In the #interface:
Deck *myDeck;
In my init method:
Deck *ourDeck = [[Deck alloc]init];
myDeck = ourDeck;
So this seems to create the myDeck just fine, and I can stick values in it and run it's methods for a while, but I'm running into a spot where it ceases to exist and I get an EXC_BAD_ACCESS error when trying to use it.
I have tried adding
[myDeck retain];
to no avail, it still fails in the same spots. I don't really know how I should be alloc and initting this, I have a feeling I am missing something, anyone?
Everything you're doing there seems right; except I think you might have a typo in your first example - the instance variable is called myDeck, not deck, right? If your object is disappearing it's because you called release or autorelease too many times. Memory management in Cocoa is pretty straightforward. Go check out the documentation for all the information you could ever want.

Checking for a valid delegate object before sending it a message

I am trying to implement the delegate Pattern in Objective-C, however I am experiencing a Bad Access exception when invoking the delegate sometimes. It seems this is caused by the delegate being released. Apple does not recommend to retain delegates.
How can I check my delegate if is still valid before trying to send it a message?
If there's a chance that the delegate will get released by the setter, then there's something wrong with your design. You should only set delegates on objects that have a shorter lifespan than the delegate itself. For example, setting a delegate on a subview/controller is fine, because the subview/controller has a shorter lifespan than the caller.
AFAIK, there is no reliable way to detect if an object has been released already.
What Apple means about not retaining delegates is that objects should not retain their delegates because they don't own them. These are only objects that handle messages.
That doesn't mean that you shouldn't retain delegates at all. The object that creates the delegate needs to own it. In the context of non-GC apps this means it should handle the retain and release cycle, and for GC apps, it means that the controller object keeps hold of a pointer to the delegate in an iVar.
without seeing some code or the error message, it is hard to find the root of this problem.
In a photoviewer application I'm using asynchronous http to load images; it happens that the user often dismisses the current view (referenced by my async http object through a delegate) before the http download completed causing a BAD_ACCESS when calling the view controller delegate method. I solved this by setting the .delegate to nil inside the dealloc block of the view controller
I'd like to share my experience also, which is very similar to Nico's one.
I've been working with a modified example of LazyTablesCode, wich is an example that comes direcly from Apple and loads images in a UITableView asynchronously. Communication between the downloader and the view it's made via delegates.
In my code, I had the problem that sometimes the load of the image finishes when the form that should be called through the delegate has been released. I've been forced to add this piece of code inside the code of the viewController (dealloc method):
if (self.nsDictionaryWithObjectsDownloading != nil) {
for (id theKey in self.nsDictionaryWithObjectsDownloading) {
Myobj *downloader = [self.nsDictionaryWithObjectsDownloading objectForKey:theKey];
downloader.delegate = nil;
}
}
It seems that these lines are solving the problem. Anyway It would be very appreciated opinions about if it's a good solution or not or even about memory issues when doing downloader.delegate = nil;
Thanks and greetings,