NSArrayController & Bindings

Discussion in 'Mac Programming' started by BadWolf13, Feb 27, 2010.

  1. BadWolf13 macrumors 6502

    Joined:
    Dec 17, 2009
    #1
    Ok, I have no idea what I'm doing wrong, but I think I've tracked it down to a bindings issue.

    My application is essentially an array, displayed in a tableview. I have a class called AppController, which contains an NSMutableArray of a custom class.

    In the Interface Builder, I put the tableview, plus add and delete buttons. I dragged an Array Controller object as well as an instance of AppController into the doc window. The Array Controller has it's content array binding(bound?) to the AppController object, and has the instance variables bound to the tableview. The Add and Delete buttons are linked to the add: and remove: objects of the Array Controller.

    Now onto the program. The program starts fine, and due to code that I entered into the init method of the AppController, it starts with 3 items in the array, all of which are displaying fine in the tableview. The problem is that whenever I click either the Add or Delete buttons, the program freezes, and the bottom of the XCode window says "EXC_BAD_ACCESS". Any ideas on what I'm doing wrong?
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    Post you code. Otherwise we are just guessing.
     
  3. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #3
    Well dude, there's not really much code at all, because it's using bindings.

    There's AppController.h which does this;

    Code:
    #import <Cocoa/Cocoa.h>
    @class Part;
    
    @interface AppController : NSObject {
    	NSMutableArray *partsList;
    }
    @end
    
    And AppController.m which does this;

    Code:
    #import "AppController.h"
    #import "Part.h"
    
    @implementation AppController
    
    -(id)init
    {
            [super init];
    
    	partsList = [[NSMutableArray alloc] init];
    	
    	Part *p = [[Part alloc] init];
    	int i;
    	for (i=0; i<3;i++){
    		[partsList addObject:p];
    	}
    	return self;
    }
    @end
    
    
    As you see, not a whole heck of a lot of code to cause an issue.
     
  4. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #4
    All it takes is one significant error.

    For example, the red-hilited code is wrong. If it's not clear why, you should review the reference docs on how to write an init method properly.

    Is that the cause of the problem? I can't tell. But it doesn't mean the wrong code is any less wrong. It does, however, make me question whether your Part code is written properly.
     
  5. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #5
    You're gonna have to explain why that's wrong. In Cocoa Programming for Mac OS X, it says that if you override the init method in any subclass(in this case, a subclass of NSObject), you need to access the superclass's init method. So I don't understand why that's wrong. Could you please explain it in depth?
     
  6. ChOas macrumors regular

    Joined:
    Nov 24, 2006
    Location:
    The Netherlands
    #6
    I have the same book, and I must say I don't see the error either.

    (As far as I know [super init] is equal to self = [super init])

    Any more information on your Part class ? (I see you don't release it after adding one instance of it (the same one) three times to the array)
     
  7. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
  8. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #8
    ChoAS, I'm using garbage collector, and my understanding is that I don't need to use "release", "retain" and all that when the garbage collector is on. Am I right?

    Here's my Part code.

    Code:
    #import <Cocoa/Cocoa.h>
    
    @interface Part : NSObject {
    
    	NSString *partNumber;
    	NSString *manufacturer;
    }
    
    @property (readwrite, copy) NSString *partNumber;
    @property (readwrite, copy) NSString *manufacturer;
    @end
    
    Code:
    #import "Part.h"
    
    @implementation Part
    
    -(id)init
    {
    	[super init];
    	partNumber = @"New Part";
    	manufacturer = @"Phoenix Corporation";
    	
    	return self;
    }
    
    @synthesize partNumber, manufacturer;
    @end
    
     
  9. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #9
    It's wrong in general, because [super init] is allowed to return a different object. Heck, it's even allowed to return nil, signifying that [super init] failed, and the remainder of the calling init should not be run.

    I don't recall that the rules for writing proper inits changed any time recently.

    http://developer.apple.com/mac/libr...nceptual/ObjectiveC/Articles/ocAllocInit.html
     
  10. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #10
    Chown, I saw this in some sample code. Would you recommend using that instead?

    Code:
    if (![super init])
          return;
    
     
  11. ChOas macrumors regular

    Joined:
    Nov 24, 2006
    Location:
    The Netherlands
    #11
    Of course I do agree that error checking should be performed (though, I do have to admit that I don't do that when inheriting from NS base classes).

    The point I was trying to make is that I couldn't imagine that call being the problem.
     
  12. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #12
    If it helps anyone, I have used the debugger, and it does get through the init method without any errors, but hits an error in objc_msgSend_vtable4. Does that make sense to anyone?
     
  13. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #13
    I guess one of my points is that just because you can't imagine something being a problem, it doesn't necessarily mean it isn't a problem. In a way, that's kinda the point of testing and debugging your code. What you believe is true isn't necessarily true in fact. Beliefs can be an obstacle to seeing problems.

    "It isn't what we don't know that gives us trouble, it's what we know that ain't so." -- Will Rogers
    Non-belief is even the basis for a programming discipline: Test-Driven Development (TDD). In essence, your code is only as good as the automated tests that can be run on it, and assertions tested thereby. Even TDD has limits, though: I have seen cases where the code under test was fine, but the test itself had subtle errors or interactions that triggered unexpected results. Unwarranted confidence was granted to the tests, and unwarranted skepticism to the code, which delayed finding the real problem. You can write tests to test your tests, but that can turn into infinite regress.

    http://en.wikipedia.org/wiki/Test-driven_development

    Frankly, I think you're going to have to improve your friendship with the debugger in order to solve this problem. Either that, or post your entire project as a zip and see if anyone else is willing to try debugging it for you.
     
  14. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #14
    Google it.

    I did, and several hits on the first page specifically mention NSArrayController. One of them even reads like surprisingly like your original post: troubles with add, etc.

    Also, any use of an objc_msgSend function is inevitably tied to some message being sent to some object. Find what that message is, and what object is the target, and debug from there.


    Finally, just because it gets through init without triggering an error doesn't mean init is blameless. Many errors are caused by code that is far distant in time or place of execution where the error finally occurs. For example, stomping on memory or failing to keep memory around will cause problems later, even if the immediately relevant code proceeds without fail.

    That's a logical argument related to beliefs and debugging. I'm not necessarily saying that your init is causing problems.
     
  15. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #15
    Well Chown, the code successfully adds three instances of Part to the array without any problems. Doesn't that logically suggest that the problem is with the bindings, not with the init method that works fine when called by code?
     
  16. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #16
    Not necessarily. It may be so in this particular case, but it's not a logical consequence that holds in all cases.

    Your earlier statement was "it does get through the init method without any errors". The unstated implication is that as a result of getting through init, it somehow proves there are no errors being caused by init. I'm saying that this conclusion isn't necessarily true.

    It's entirely possible that errors can occur in init that don't cause failures until later. For example, if you allocated but failed to init some object. Or you allocated some memory but overflowed it, thus stomping on other memory. Or you could even have neglected to alloc or init some instance variables, so they'd be nil, which might lead to unexpected errors later. Those are all cases where getting through init without any failures occurring is not proof (or even strong evidence) that the code is correct.

    I'm not saying any of those things are happening here. I'm just pointing out that your earlier statement ("it does get through the init method without any errors"), and the implied conclusion are not necessarily true in every situation.
     
  17. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #17
    Chown, I'm not interested in getting into a logical debate, or talking about hypothetical situation when you can see all the code in the program.

    Also, if [super init] is the problem, can you explain when that's called by the remove: method?
     
  18. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #18
    If you're not interested in getting into a logical debate, then why are you asking a question about logic? (That's a rhetorical question. If you answered it, you'd be engaging in a logical debate, which you've already declined to do.)

    Instead of getting mired in hypotheticals, or trying to show flaws in my logic, why don't you apply some of my other suggestions?

    Specifically, I suggested finding out what message is being sent when objc_msgSend_vtable4 fails. This will require spending time in the debugger. You might also want to read the results from the google search I pointed out.

    I also suggested posting the complete project. I mention this in particular because without the rest of the project, and having only your posted code, it's not possible to accurately reconstruct an exact duplicate of your project.
     
  19. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #19
    Truth be told, I thought your other suggestions were rhetorical. I didn't think you'd actually expect someone to post their entire project online for someone else to pick through. I'm learning the language because I want to be able to write my own programs, not have someone else do it for me.
     
  20. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #20
    From your description, it seems to be a small project at this point. That's just the sort of thing to post in its entirety. Especially if the problem appears to be somewhare other than the source code, such as objects stored in nibs/xibs. Posting actual nibs/xibs is the equivalent of "Post your code".

    For example, see this post which includes zipped code:
    http://forums.macrumors.com/showthread.php?t=870987

    In the past, when people have posted entire projects, and someone looks at them, mistakes in nibs/xibs have been found and duly described in replies. It's not all that unusual.
     
  21. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #21
    Well, if the error happens when you click a button, would you not then first consider looking at the actions?
     
  22. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #22
    Sydde, the action of the "add" button is the "add:" method of the Array Controller. Since the Array Controller is only in Interface Builder, without any code, I'm not sure how to examine it any further. Any suggestions for that?

    I can't remember if I explained it originally, but I'm using a subclass of NSObject called Array Controller which holds the Content Array Binding of the Array Controller. Could there be an issue from that?

    I'd show you the bindings screenshot, but I can't seem to figure out how.
     
  23. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #23
    Ok, update on this problem. I've gone around the "add:" problem without actually solving it by creating my own "createPart:" method. However, for some reason, when it adds the new object, for some strange reason, the original 3 are selected automatically. I could easily write code to make it select the new part, but I want to know why this would happen, and I don't have any ideas. Anyone got any idea?
     
  24. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #24
    Is "Preserve Selection" checked in Interface Builder?
     
  25. BadWolf13 thread starter macrumors 6502

    Joined:
    Dec 17, 2009
    #25
    I must be looking in the wrong place, cause I don't see that anywhere in the Attributes for the Table View.
     

Share This Page