I was testing my application and suddenly it had EXC_BAD_ACCESS. Now this has become a semi-regular thing, happening on some builds and not others. It also spits out lots of errors in the debugger such as objc_msgSend_vtable5 What could cause such a weird issue like this?
Looks like it was my fault. To fix it all I needed to do was call retain.
I've recently had just this same error. The short version: it occurred because I had an object that had a delegate that had been released. Make sure you have control over the life cycle of any delegates you assign, be it via Interface Builder or otherwise.
The long version: the error occurs when the Objective-C runtime tries to send a message to an object that's been ultimately released and deallocated. This is different to sending a message to a nil object (a perfectly valid Objective-C operation). In these cases, the runtime knows that the object is nil and responds accordingly. Rather, in this case, Objective-C thinks it has a real, valid object to communicate with and sends a message to an address that contains no object.
In my case, I had an object of type NSTextView which was connected up to a delegate by Interface Builder. When a view or view controller is constructed with a NIB/XIB file, Cocoa hooks up all the child views as instructed, including hooking up any delegates that you might have.
My error was that I had created a subclass of NSView, made it an NSTextViewDelegate and then told Interface Builder to hook up a child NSTextView to that parent view. However, during the various operations I was conducting on the owning NSViewController, I had told Cocoa to remove the NSView from the view hierarchy and reinsert it later.
AppKit specifically tells you not to retain any IBOutlets you might have in your classes, but rather to keep track of these by simple assignment. This is because AppKit handles the memory management of these for you. Little did I know that by asking the view to leave the view hierarchy for a while, I had trigged AppKit to clean up that NSView. Since only AppKit had any retains on the view object itself, [pfft], off it went into the ether. Deallocated.
Since I had no direct control over the NSTextView's delegate, the NSTextView now pointed to a delegate that had been released, even though it had a valid parent view. The next time it tried to send a message to its delegate, the Objective-C runtime fell over.
So, make sure that the delegate is one that you own, or at least know will never get released at an inopportune moment.
Related
I have an NSArrayController bound to CoreData in my application. It is also bound to a TableView that displays the data. Two buttons are bound to the ArrayController that add and remove lines. All of this is working as expected. I can add, edit, save, and remove CoreData Entries.
There is a section of my app that is to accept drag and drop operations from files (working). It takes the data from the files, looks for various information, and is to insert this information into the Core Data database via the NSArray Controller.
I have added the class handling the parsing/adding of the file to the database as an object in IB. I created an IBOutlet for the array controller in the class, and bound the controller to the class' referencing outlet.
If I add a button to the interface to directly call the method that adds a custom record to the database, everything works. If the method is called via the drag and drop operation, nothing works, even logging a simple [arrayController className] returns null (though returns NSArrayController as expected when the method is called from the button click).
The only difference I can see is that when accessed through the button click, the method is called directly, while the other way passes through my drag and drop class before loading the parsing class, but I'm completely stuck on how to remedy this situation. I'll be happy to provide code, just not sure which code you'll need.
Any help is appreciated. Thanks!
==================
UPDATE
turns out I was connecting the IBOutlet to a class (a subclass of a view) object in IB instead of to the view itself handling the drops. Connecting these up made things work. Well, not work, I have other issues to iron out now, but the Array controller is now instantiated.
Moved from comment to answer: The array controller you are trying to add stuff is not instantiated. I assume you are not referring to your original NSArrayControllerinstance but maybe a new created one? Probably a problem of communication between your class instances.
Debugging this should be straightforward ... using the debugger. Set a few breakpoints (one at each action the button(s) call, and one at each point where your class instances are meant to talk to each other (your importer and your main controller)). Run, test, step through the code when the debugger breaks at each breakpoint.
My guess: An outlet is not hooked up (is nil) in IB or is not yet reconnected at runtime (see -awakeFromNib and make sure you're not trying to touch an outlet or action that hasn't been fully reconnected from the nib at runtime by the time you're trying to use it).
Something’s not hooked up right, BUT you don’t want to do it this way anyways. There’s no advantage to inserting via an NSArrayController. Just create new objects with NSEntityDescriptions:
+ (id)insertNewObjectForEntityForName:(NSString *)entityName inManagedObjectContext:(NSManagedObjectContext *)context;
And you’re done. If your NSArrayController is hooked up correctly it’ll auto-fetch the new objects at the end of the event so the user will see them “immediately.”
I added ARC to an app I'm working on. Unfortunately, it crashes. I found that the automatic script which updates all apps to ARC gave __unsafe_unretained qualifier to all id< protocolName> type.
Why isn't it a weak type? I have deployed the app and all its sub-projects to iOS 5, and therefore I do have weak qualifiers.
My main problem is if I declare those delegates as strong, I'll have a retain-cycle. If I do not, the next time I call them they will be zombies. I checked and before my app crash, the delegate is NSZombie.
What is the cause of this crash and how can it be prevented?
The qualifiers __unsafe_unretained and week have quite a few things in common. They both won't increase the retain count for example. If for example a view controller holds an __unsafe_unretained IBOutlet to a UIView and you remove that very UIView from the view hierarchy, then you (given that you don't retain the view anywhere else) will decrease the retain count and most likely dealloc the UIView. The pointer however will still point to that location and is left dangling. Not nice but also not problematic if you know what happened. Weak properties help you avoiding dangling pointers by nullifying the property when the object gets to a retain count of 0.
Now, if your app crashes or the properties show up as zombies, then they are being released - by whichever class though.
One statement that is not entirely correct is that if you retain the property instead, you'll create a retain cycle. There is the possibility of creating retain cycles though but it really depends on your implementation, not just the property declaration. When you retain an object, you take ownership and until you're done with that object, prevent it from being deallocated by increasing its retain count. If your delegate gets released already while you hold a weak pointer, you won't prevent it from being released. I am assuming you deal with modal view controllers here - UIPopoverController to be precise (just a guess).
You should use instruments and look at the lifecycle of your object and see who retains/releases it. It could be helpful to know. Otherwise, you could paste some code and maybe there will be a nice person here to help you find the issue.
cheers
Ronny
Took some time but i solved it:
I deployed the .xcodeproj projects to iOS 5, but the targets were left in iOS 4.3 deployment. When i fixed it (it's in the 'build settings' for each target) - i could change all '__unsafe_unretained' to '__weak', and all 'unsafe_unretained' to 'weak'.
To avoid retain cycle those delegates should be weak, and they won't be zombies anymore (because they are weak and not unsafe_unretained), and the app won't crash anymore.
If i was still using iOS4.3-, and there isn't unsafe_unretained qualifer, i should only assign nil to those delegates after i don't need them anymore.
I know the question is a bit generic but I guess my issue is generic as well.
I'm developing a small application in my free time and I decided to do it with Cocoa. It's nice, many things works almost automagically, but sometimes it's quite hard to understand how the framework works.
Lately I'm facing a new problem. I want to manage all the windows of the application from a single class, a front controller basically. I have a main menu and an "Import data" function. When I click it I want to show another window containing a table and call a method for updating the data. The problem is that this method is inside the class that implements the NSTableViewDataSource protocol.
How can I have a reference to that class? And more important, which should be the right way to do it? Should I extend the NSWindow class so that I can receive an Instance of NSWindow that can control the window containing the table (and then call the method)?
I may find several ways to overcome this issue, but I'd like to know which one is the best practice to use with cocoa.
PS: I know that there are tons of documentations files, but I need 2 lives to do everything I'd like to, so I thought I may use some help asking here :)
The problem is that this method is inside the class that implements the NSTableViewDataSource protocol.
How can I have a reference to that class?
These two sentences don't make sense, but I think I understand what you're getting at.
Instead of subclassing NSWindow, put your import window's controlling logic – including your NSTableViewDataSource methods – into a controller class. If the controller corresponds to a window, you can subclass NSWindowController, though you don't have to.
You can implement -importData: as an IBAction in your application delegate, then connect the menu item's selector to importData: on First Responder. That method should instantiate the import window controller and load the window from a nib.
In your import window controller's -awakeFromNib or -windowDidLoad method, call the method which updates the data.
Added:
Here's the pattern I'd suggest using in your app delegate:
#property (retain) ImportWindowController *importWC;
- (IBAction) showImportWindow:(id) sender {
if (!self.importWC)
self.importWC =
[[ImportWindowController alloc] initWithWindowNibName:#"ImportWindow"];
[self.importWC refreshData];
[self.importWC.window makeKeyAndOrderFront:sender];
}
The title question arises for me when working in many areas of the application: models, controllers, getters, setters, actions, etc. I have a Core Data document-based application and I constantly need to get a reference to the current NSMangedObjectContext object.
The current scenario involves a custom controller I made to handle "simulations" (this application simulates a particular kind of mathematical model.) There is a button called "Simulate" and it is bound to an action in the simulation controller. The simulation controller needs to get information from the current document i.e. information from the NSManagedObjects in the current managed object context.
The simulation controller is a subclass of NSObjectController which has a method called managedObjectContext but when I call that method, I get nil. I'm not sure why nil is returned but I do know that the controller is not acting on behalf of any managed objects. It's controlling the simulator, which is not a model in MVC. The controller is an interface between the views, models, and the simulator.
How do I get the NSManagedObjectContext that is storing NSManagedObjects for the currently open window? The currently open window has views showing information from objects in the context, and the simulation button is in this window's toolbar.
Update:
Well... thanks to TechZen for opening my mind a little... or maybe it was just taking a break and going to a BBQ...
For this particular scenario the answer is:
Bind the managed object context in Interface Builder to my controller (the controller was created in interface builder and then I changed the class to be my subclass of NSObjectController). This setting can be found in the Bindings Inspector under Parameters and is called Managed Object Context. I set it to bind to the File's Owner and the model key path to "managedObjectContext".
Then, the message "managedObjectContext" works within my controller just like:
[self managedObjectContext];
This, however, still doesn't fully answer my question because I'd also like to get a reference to a managed object context in a class method of a subclass of NSManagedObject. So if the simulation controller then creates a new NSManagedObject by calling a class method on my subclass of NSManagedObject, I'd like that method to have a reference to the context and create the object. And I do not want to pass the context to the method... I feel like the class methods should be able to get the context... I remember seeing code like:
[[NSApp delegate] managedObjectContext];
But this didn't work for me. But if it did, this would be an excellent solution becauxe NSApp is global and returns the current NSApplication instance.
Update:
Well, after a lot of reading and Googling... I discovered that I was just totally off the mark in the design of my application. Instead of having a simulation controller receive the click of the simulation button, I created a custom NSWindowController for that window and it receives the simulation button click event (a kind of IBAction). NSWindowControllers have a reference to the NSPersistantDocument, which has a reference to NSManagedObjectContext. And this custom window controller I wrote get's that NSManagedObjectContext and passes it to the simulation controller... and the world is filled with joy. Not sure how useful this is to others, since this question and answer are now littered with noise.
If you are using a Core Data document based application, then each document will be an instance of NSPersistentDocument which will have its own NSManagedObjectContext for just that single document.
You can get the context by:
NSManagedObjectContext *context=[aPersistentDocument managedObjectContext];
Update:
With a document based app, you don't have a single, central or master managed object context because each document has it's own wholly independent Core Data stack from the store to the context. You end up with as many context has you have open documents.
This contrast with a more database like design in which the entire app has only those stores and context defined when the app was coded. In that case, you may have only one context that is used everywhere in the app. In that case, you can park the context in the app delegate and access it from anywhere.
It's bad design to have a class or instance method in a NSManagedObject subclass that finds a context because this limits the flexibility of the use of the subclass. To do so the class would have to be wired into the structure of a specific app so the subclass could only be used in a specific design where it could find the context. If you changed anything about the location of the context or the use of the subclass, you would have to write it all over again.
I think you need to back out and rethink your design and decide if you want a document based app or a more database-like app. I would recommend reading:
Document-Based Applications Overview and NSPersistentDocument Core Data Tutorial
I've got an application with an NSLevelIndicator Object on it that's refusing to update.
I have a timer that's shoved off during init and updates the value of the NSLevelIndicator using its setIntValue method. Whilst the code executes without any exceptions, the NSLevelIndicator never visually updates. I have some other labels on the window that are updating through this timer, so I know that it is executing.
I've tried using all of the setTypeValue methods (String, straight value and double with appropriate variables being assigned in each). I even tried linking the "setStringValue" action through interface builder from the NSLevelIndicator to a label representation on the window to no avail. It still sits at its initial value (0).
I noticed that setIntValue (and all the other setTypeValue methods) are undocumented in Apple's documentation for NSLevelIndicator - so I'm wondering if I'm approaching this wrong.
Does anyone have any clue what the proper way to set an NSLevelIndicator's value from code is?
setIntValue should work, so it sounds like your IBOutlet for the NSLevelIndicator isn't set properly - most likely its value is nil.
This is probably due to your outlet not being connected in IB, as Johan Kool suggested.
One thing worth mentioning, however, is that IBOutlets don't yet have a valid value at the time your initializer is called - they're hooked up after the initializer returns and shouldn't be referenced until your instance receives the awakeFromNib message.
You mentioned your timer is set up from your initializer - if you happen to be passing your instance's NSLevelIndicator pointer to the timer as its userInfo parameter, the userInfo will have the wrong value (nil) since it isn't yet initialized when the timer is created.
Regardless of whether you use userInfo this way, anything that depends on IBOutlet values should be set up from within awakeFromNib rather than init.