I wouldn't normally ask questions like this, but I really cant get my head around it. I have a class 'GetTableInfoFromDatabase', which connects to my database and downloads some JSON. This works great from the first screen of my tab-bar application. I can call the getNewData method as much as I want to effectively refresh the data.
My problem arises when I try and create an instance of the 'GetTableInfoFromDatabase' class and call the very same method from another tab. I get the following error:
*** -[GetTableInfoFromDatabase respondsToSelector:]: message sent to deallocated instance 0x1d89e830
The funny thing is, i'm using ARC. The culprit (in my opinion) is ASIHTTPRequest. I have had to enable -fno-objc-arc to get the project to compile. This library is used in the GetTableInfoFromDatabase class.
Here is the class:
- (void) getEventDataWithSender:(id)sender{
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:#"-------.com/getdata.php"]];
[request setDelegate:self];
NSLog(#"Running!");
[request startAsynchronous];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.managedObjectContext = appDelegate.managedObjectContext;
}
And this is how i'm calling it:
GetTableInfoFromDatabase *getInfo = [[GetTableInfoFromDatabase alloc]init];
[getInfo getEventDataWithSender:self];
I've even changed the order of the tabs around, so the first tab to be displayed purely just calls this method, nothing else. Not even before the 'GetTableInfoFromDatabase' has been previously initialised by the class that initialised it first last time. Still crashes.
Has anyone got any ideas? This is so frustrating!
You need to assign that variable to a property if you plan on exposing it to other view controllers. ARC will, and should, immediately deallocate getInfo after this code executes:
GetTableInfoFromDatabase *getInfo = [[GetTableInfoFromDatabase alloc]init];
[getInfo getEventDataWithSender:self];
So if this line is included in say viewDidLoad: and nothing else refers to getInfo in that method, it will be immediately released. Why, because you haven't told the compiler that it should retain it.
So in the view controller that's exposing this class, on whatever tab it might be a child of... you would do something like this:
ViewController.h
#class GetTableInfoFromDatabase; // forward declaration
#interface ViewController : UIViewController
#property (strong, nonatomic) GetTableInfoFromDatabase *getInfo;
ViewController.m
#implementation ViewController
#synthesize getInfo = _getInfo;
- (void) viewDidLoad {
[super viewDidLoad];
self.getInfo = [[GetTableInfoFromDatabase alloc]init]; // assign your value to a property
[self.getInfo getEventDataWithSender:self];
}
So when you declare your property as Strong in your header, it will maintain a strong reference to it. #Synthesize getInfo = _getInfo means that it will create a getter and setter for self.getInfo around an instance variable named _getInfo. If you didn't want to expose it as a property, just an instance variable... you could do this:
ViewController.h
#class GetTableInfoFromDatabase; // forward declaration
#interface ViewController : UIViewController {
GetTableInfoFromDatabase _getInfo;
}
ViewController.m
#implementation ViewController
- (void) viewDidLoad {
[super viewDidLoad];
_getInfo = [[GetTableInfoFromDatabase alloc]init]; // assign your value to a property
[_getInfo getEventDataWithSender:self];
}
By default, the compiler will maintain a strong reference to that instance variable unless otherwise specified. You can have weak references as well, and all of those options are pretty well documented. So with ARC, or plain old memory management in general, you need to make an instance variable or property if you want it to hang around for a while.
Honestly... all ARC is doing for you is keeping you from having to call retain and release. Before ARC, setting that property would look like this:
GetTableInfoFromDatabase getInfo = [[GetTableInfoFromDatabase alloc]init];
self.getInfo = getInfo;
[getInfo release];
Now with ARC, the compiler just writes that code for you ;) Hope this helps!
[self.getInfo getEventDataWithSender:self];
Your GetTableInfoFromDatabase object is being deallocated, almost certainly because nothing is holding a strong reference to it. In your code above, getInfo is a local variable, so I would expect it to be released very shortly after this code, unless you are storing it somewhere.
Almost certainly, your dealloc in GetTableInfoFromDatabase does not clear the request's delegate. You should be holding the request in an ivar of GetTableInfoFromDatabase so that it can remove itself as delegate when it is deallocated.
As a side note, avoid prefacing ObjC methods with get. That has a special meaning in KVC (it means that the first parameter is supposed to be updated by reference). Typically the kind of method you have here would be prefaced with "fetch."
Related
I have an App with an NSWindowController and an associated XIB which is not needed most of the time (admin interface window), so I wanted to use Lazy instantiation. However, I also need to setup the 'delegate' and that is when the errors happen.
I have everything setup in the AdminWindow,h (subclass of `NSWindowController') and .m file.
In my main controller, MainController (subclass of NSObject) I have the following working code.
#interface MainController : NSObject<AdminWindowDelegate>{
AdminWindow *myAdminWindow;
}
#implementation MainController
-(id)init{
myAdminWindow = [[AdminWindow alloc] init];
[myAdminWindow setDelegate:self];
}
-(IBAction)openAdminWindow:(id)sender{
[myAdminWindow showWindow:nil];
}
So that all works, but I don't want to instantiate myAdminWindow until it's needed, thought lazy instantiation would work.
Altered the MainController:
#implementation{
-(AdminWindow *) myAdminWindow{
if(!_myAdminWindow){
_myAdminWindow = [[AdminWindow alloc] init];
//Tried to set delegate here, but does not work
}
-(IBAction)openAdminWindow:(id)sender{
[self.myAdminWindow showWindow:nil];
}
Where do I set the delegate? I tried just after 'alloc' 'init' of myAdminWindow, but it does not work. when I start typing the command
_myAdminWindow.setDe... Xcode gives nothing, .setDelegate or .delegate are not options.
I've tried
[_myAdminWindow setDelegate Nope, does not work either.
Leaving out the delegate portion, everything else works as desired.
Question: When using lazy instantiation , where do I set the delegate? and how?
Thank you in advance
===[EDIT]===
In case someone else has the same question.
Thank you to Phillip Mills for the reply and reminder.
I removed the following declaration in #interface of MainController:
AdminWindow *myAdminWindow;
And declared myAdminWindow in the MainController's interface section as a property - and all is good!
I'm trying to access a property in my app delegate from another class (something I thought would be rather simply) but I'm having troubles in doing so. My files currently look like this:
LTAppDelegate.h
#import <Cocoa/Cocoa.h>
#import "Subject.h"
#interface LTAppDelegate : NSObject <NSApplicationDelegate, NSOutlineViewDelegate, NSOutlineViewDataSource, NSMenuDelegate> {
}
#property Subject *selectedSubject;
#end
LTAppDelegate.m
#synthesize selectedSubject;
The value for selectedSubject is then set inside applicationDidFinishLaunchingin LTAppDelegate.m. Now I'm wanting to get access to this from another class that I have, which is called LTTableViewController and is setup like so:
LTTableViewController.h
#import <Foundation/Foundation.h>
#import "LTAppDelegate.h"
#import "Subject.h"
#import "Note.h"
#interface LTTableViewController : NSObject{
NSMutableArray *notesArray;
LTAppDelegate *appDelegate;
Subject *s;
}
-(IBAction)currentSubjectDetails:(id)sender;
#end
LTTableViewController.m
#import "LTTableViewController.h"
#implementation LTTableViewController
- (id)init
{
self = [super init];
if (self) {
appDelegate = ((LTAppDelegate *)[[NSApplication sharedApplication] delegate]);
s = [appDelegate selectedSubject];
NSLog(#"Test Subject: %#", [s title]);
}
return self;
}
-(IBAction)currentSubjectDetails:(id)sender{
NSLog(#"Selected Subject: %#", [s title]);
}
After inserting various NSLog() messages it would appear that the init method of LTTableViewController is called before applicationDidFinishLaunchingis called in LTAppDelegate. Based on that it makes sense that the "Test Subject" NSLog() in LTTableViewController.m init displays null; however, the 'currentSubjectDetails' method is linked to a button on the interface and when that is pressed after the app is finished loading, the NSLog() message still returns null.
Is there anything obvious I'm missing here. I feel like I'm being a little stupid and missing something really basic.
Similar issue is described here http://iphonedevsdk.com/forum/iphone-sdk-development/11537-viewcontroller-called-before-applicationdidfinishlaunching.html Adding this kind of functionality in the constructor is usually not recommended. Generally, I'd suggest using parameters and not relying on hidden dependencies as those will necessarily depend on the order of execution and you lose the help of the compiler to avoid invalid values. View controller initializers should not be used to store mutable references since view controllers are initialized automatically by predefined constructors, and you cannot pass parameters to them this way.
If you need to access the app delegate, then obtain it, perform operations on it and drop the reference. Try not to cache it, you'll very likely introduce hidden issues. I suggest you hook into the appear-disappear cycle if the viewed contents depend on any kind of current state.
Well, s does not exist, since it is set to null in init, so -currentSubjectDetails prints null. It is not a good idea to set your private variables in the constructor if they depend on other objects.
Rather, let the other objects explicitly tell your controller that it should use that Subject (e.g., treat s as a property).
Or, just query ((LTAppDelegate *)[[NSApplication sharedApplication] delegate]); every time.
-applicationDidFinishLaunching called when e.g. all nib's object initialized, so launching will be ended after construction of views related stuff. This means that constructors of nib's objects wouldn't use any other nib's objects (your delegate and controller initializing with nib, right?).
Try to use -awakeFromNib instead of constructors, I think it will called after construction of both objects.
If you are trying to avoid often calls of ((LTAppDelegate *)[[NSApplication sharedApplication] delegate]) I'll recommend to pass it as method parameter, in function stack. Cyclic references defense and some flexibility.
I am having a very, very strange error, probably related to memory management (even though I'm using ARC).
I have a my AppDelegate, Foo, and SubFoo (which is a subclass of Foo).
Foo.h
#protocol FooDelegate <NSObject>
- (void)didReceiveDownloadRequest:(NSURLRequest *)downloadRequest;
#end
#interface Foo : NSObject {
__weak id <FooDelegate> delegate;
}
- (void)performRequest;
#property (nonatomic, weak) id <FooDelegate> delegate;
#property (nonatomic, retain) NSString *fileIdentifier;
Foo.m
#implementation Foo
#synthesize delegate, fileIdentifier;
- (id)init {
if ((self = [super init])) {
self.delegate = nil; // I tried leaving this line out, same result.
NSLog(#"I am %p.", self);
}
return self;
}
- (void)performRequest {
// Bah.
}
#end
SubFoo.h
#interface SubFoo : Foo {
WebView *aWebView;
}
SubFoo.m
- (void)performRequest {
if (self.fileIdentifier) {
aWebView = [[WebView alloc] init];
[aWebView setFrameLoadDelegate:self];
[[aWebView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"theURL"]];
}
}
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
NSLog(#"Finished loading.");
// ...
NSLog(#"Class Name: %#", NSStringFromClass([self class]));
NSLog(#"Memory Location of delegate: %p", self.delegate);
// ...
}
Sometimes, the class name on webView:didFinishLoadForFrame: returns a completely different class (instead of SubFoo, it returns random classes, like NSSet, NSArray, it even sometimes returns CFXPreferencesSearchListSource), other times it just crashes there with an EXC_BAD_ACCESS, and when it returns a random class on Class Name: it returns that [randomClassName delegate] is an unrecognized selector.
EDIT: When self gets set to another thing, it gets set RIGHT on webView:didFinishLoadForFrame:, and on performRequest it is ALWAYS SubFoo.
Any help here would be appreciated.
First, even though you are using ARC zeroing weak references in your project (#property (weak)), other projects and frameworks may not be (and are probably not) using zeroing weak references.
In other words, assume that all delegates in frameworks are __unsafe_unretained unless:
The delegate property is declared weak in a header
The documentation/header explicitly states otherwise
That said, let's talk about your example. Your object ownership chart looks something like this:
(Note: I'm not entirely sure which class in your project uses SubFoo. Based on common practice, I'm assuming that you have a class with a strong reference to SubFoo, and that class is also set up to be a SubFooDelegate)
Ultimately, your instance of SubFoo is losing its last strong reference and is deallocating. In a perfect ARC-enabled world, the WebView's pointer to SubFoo would nil out at this time. However, it's not a perfect world yet, and WebView's frameLoadDelegate is __unsafe_unretained. Due to run loop interaction, the WebView is outliving SubFoo. The web request completes, and a dead pointer is dereferenced.
To fix this, you need to call [aWebView setFrameLoadDelegate:nil]; in SubFoo's dealloc method. You also need to call it when you reassign aWebView, as you are losing track of the old aWebView:
SubFoo.m
#implementation SubFoo
- (void)dealloc {
[aWebView setFrameLoadDelegate:nil];
// Also nil out any other unsafe-unretained references
}
- (void)performRequest {
if (self.fileIdentifier) {
[aWebView setFrameLoadDelegate:nil]; // Protects us if performRequest is called twice. Is a no-op if aWebView is nil
aWebView = [[WebView alloc] init];
[aWebView setFrameLoadDelegate:self];
[[aWebView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"theURL"]];
}
}
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
// ...
}
Forget the self.delegate error for now, it is a red herring if [self class] is producing the wrong result! Your results suggest you are somehow clobbering self.
Breakpoint on webView:didFinishLoadForFrame: check the self value and step through.
Comment Followup
For self to be wrong on the first statement of an instance method is, let's say, unusual (but not impossible).
It is important when an object is set as another's delegate that you make sure the delegate object's lifetime is at least as long as the one it is acting as a delegate to. Introducing ARC can make previously working code fail as it may release the delegate earlier than the code did under MRC. When this happens the call to the delegate usually fails.
However your error does not fail on the call to the delegate; the call starts - you end up in webView:didFinishLoadForFrame: - and then you find self is invalid. To actually invoke an instance method usually requires a valid value for self as it is used to determine the method implementation to call. Hence it is usual for self to be valid at the start of a method!
But note the "usually"...
So despite you having successfully reach your method, your error might be down to not having a strong reference to your SubFoo instance, you pass it as a delegate to aWebView, and by the time webView:didFinishLoadForFrame: is called your SubFoo has gone.
Make sure you're keeping a strong ref to your SubFoo instance. If you just want to test (this is not a recommended general solution!) if this is your problem you can just assign it to a local static (static SubFoo *holdMe say declared inside performRequest) in performRequest, which will keep a strong reference around at least until the next call to performRequest. If this does prove to be the problem you then need to come up with a good way to maintain the reference that fits your design.
Here's the real problem: You're creating a SubFoo object within the context of a method. So after the method completes, SubFoo is being released (before its WebView has time to load).
To fix this, you'll need to assign the SubFoo object you're creating to something persistent, like a instance variable of the class you're creating it from. That way the object will persist beyond the scope of the method it was created in and all will work as expected.
As CRD mentioned, I would say an incorrect object/bad access returned is a sign of an object being released. Sometimes it's replaced by another object, sometimes it's not so you get the bad access exception. Regarding how this could happen to self, I would imagine that this is a concurrency weird case (object is being freed on another thread).
The best way to confirm this is to run your code in Instrument's NSZombie template, it'll show you as soon as you access a freed object. It also shows when it's been retained/released so you don't have to guess.
Regarding your above comment.
SubFoo *theClass = [[SubFoo alloc] init];
You must store theClass in a
#property (strong) SubFoo *mySubFoo;
If you declare it as such:
{
SubFoo *theClass = [[SubFoo alloc] init];
}
It gets released at the closing bracket. This part of the point of ARC when that variable moves out of scope, it gets released. If you want to let it float in the ether you could use
{
__weak SubFoo *theClass = [[SubFoo alloc] init];
}
and it won't get released, but this will lead to a memory leak unless you carefully manage all the weak references. In the case of it not being released at -performRequest I'm assuming the request looks like this:
{
SubFoo *theClass = [[SubFoo alloc] init];
[theClass performRequest];
}
wheras -webView:didFinishLoadForFrame: is called at some indiscriminate time in the future.
I've done all sorts of research today on best practices with regards to declaring IBOutlets and instance variables, managing them, using the correct accessors and properly releasing them. I'm pretty much there, but I've got some niche questions that I hope somebody will be able to advise the best practice on. I'll format them as code and comment the questions so as to make it easier to understand. I've excluded some obvious parts that I didn't think were relevant and can be safely assumed to work (like pre-processor stuff, #end, required implementation methods etc).
MyViewController.h
#class OtherViewController;
#interface MyViewController : UIViewController {
NSString *_myString;
BOOL _myBOOL;
}
// The first two properties aren't declared in the interface
// above as per best practices when compiling with LLVM 2.0
#property (nonatomic, retain) OtherViewController *otherViewController;
#property (nonatomic, retain) UIButton *myButton;
#property (nonatomic, copy) NSString *myString;
#property (readwrite) BOOL myBOOL;
MyViewController.m
#implementation MyViewController
// Synthesizing IBOutlets on iOS will cause them to be
// retained when they are created by the nib
#synthesize otherViewController;
#synthesize myButton;
// Assign instance variables so as to force compiler
// warnings when not using self.variable
#synthesize myString = _myString;
#synthesize myBOOL = _myBOOL;
- (void)viewDidLoad {
// QUESTIONS:
// 1. Ignoring convenience methods, can you still alloc and init in dot notation
// even when it's being properly synthesized?
self.myString = [[NSString alloc] initWithString:#"myString"];
self.myString = existingNSStringObject;
// 2. Should you always call methods for IBOutlets and instance variables using dot notation?
// Is there any difference seeing as these aren't directly invoking setters/getters?
[self.myButton setText:self.myString];
[myButton setText:self.myString];
[self.otherViewController.view addSubview:mySubview];
[otherViewController.view addSubview:mySubview];
[self.myButton setAlpha:0.1f];
[myButton setAlpha:0.1f];
self.myButton.alpha = 0.1f;
myButton.alpha = 0.1f;
// 3. How fussy are scalar variables in terms of getters and setters,
// given that there is a #synthesize declaration for them?
self.myBOOL = YES;
myBOOL = NO;
if(self.myBOOL) { ... }
if(myBOOL) { ... }
// 4. On instantiation of new view controllers from NIBs, should you use
// dot notation? (I haven't been doing this previously).
otherViewController = [[OtherViewController alloc] initWithNibName:#"OtherView" bundle:nil];
self.otherViewController = [[OtherViewController alloc] ... ]
}
- (void)viewDidUnload {
// 5. Best practice states that you nil-value retained IBOutlets in viewDidUnload
// Should you also nil-value the other instance variables in here?
self.otherViewController = nil;
self.myButton = nil;
self.myString = nil;
}
- (void)dealloc {
[otherViewController release];
[myButton release];
[_myString release];
}
I always declare and explicitly set a property's underlying instance variable. It's a little more work up front, but in my mind it's worth it to explicitly differentiate variables and properties and see at a glance what instance variables a class has. I also prefix instance variable names, so the compiler complains if I accidentally type property instead of object.property.
Calling alloc / init creates an object with a retain count of 1. Your synthesized property will also retain the object, causing a memory leak when it's released (unless you release your property right after, but that's bad form). Better to alloc / and release the object on a separate line.
Dot notation is effectively the same as calling [self setObject:obj]. Not using dot notation accesses the underlying instance variable directly. In init and dealloc, always access the instance variable directly as the accessor methods can include extra operations (such as key value observing notifications) that are not valid when the object is being created or destroyed. All other times use the synthesized accessor methods. Even if you're not doing anything special now, you might later override these methods later to change what happens when the variable is set.
Scalars work the same way, only you don't have to worry so much about memory.
One accesses the synthesized accessor methods, the other accesses the instance variable directly. See questions one and two again, and be careful about memory leaks!
The view controller may be pushed onto the screen again, in which case your viewDidLoad method will be called a second time. If you're setting initial values in viewDidLoad, go ahead and set your properties to nil here. This makes sense for properties that use a lot of memory and aren't going to affect the state of the view. On the other hand if you want the property to persist until you're sure it's no longer needed, create it in your init method and don't release it until dealloc.
1) You've slightly misunderstood #synthesize. #synthesize does nothing with the object. It only tells the compiler to generate the getter and setter methods according to the options used in your #property declaration
// Synthesizing IBOutlets on iOS will
cause them to be
// retained when they
are created by the nib
The outlets aren't retained (outlets are just notices to interface builder and don't affect the code), the objects are retained when the setter generated by #synthesize is used. When the nib is loaded, the loading system calls your generated setter.
2) Deciding whether to use accessors in objective C is no different from deciding to use accessors in any other object oriented language. It is a choice of style, need and robustness. That the accessor is serving as an IBOutlet makes no difference.
But in objective C I would suggest you should NOT use accessors in two places: dealloc and within the var's accessor method itself.
And if you ARE using the accessors in init then you need to be careful about your retain counts.
self.myString = [[NSString alloc] initWithString:#"myString"];
This line leaks memory. Using your copy accessor retains the object, so you should release it here after creating it.
3) Not sure what you mean by fussy. Possibly see answer to 2)
4) See 2) and be careful about memory management. If you call alloc/init you are now responsible for releasing the object - this is entirely independent of the retains/releases used by accessors and dealloc.
5) No, you should not nil other instance variables in viewDidUnload. Your controller is expected to maintain its state even if the view goes away. viewDidUnload is only for cleaning up potentially memory-heavy view objects when the controller's view is not currently on screen.
Consider a navigation controller. View controller 1 is on the stack and then view controller 2 is pushed and is now visible. If memory conditions get low, the system could attempt to unload view controller 1's view and will then call viewDidUnload.
Then popping view controller 2 will not create the view controller 1 object again, but it WILL load view controller 1's view and call viewDidLoad.
Re comments
2) That's exactly right - you can use a convenience constructor or release immediately after your alloc/init and assignment, or release before the block exits, or autorelease. Which you choose is mostly a matter of style (though some would argue against autorelease - but not me!)
3) There are accessors for scalars - you have created some in your code
#property (readwrite) BOOL myBOOL;
This creates methods myBOOL and setMyBOOL on your class.
Remember that there is nothing special about dot notation. It is only a convenience and when the code is compiled myObject.property is exactly equivalent to [myObject property] and myObject.property = x is exactly equivalent to [myObject setProperty:x]. Using dot notation is purely a style choice.
Dot notation and brackets notation are pretty much the same.
By self.myVariable you are accessing the getter of the property of the instance variable myVariable and by myVariable you are accessing the local variable. They're not the same thing.
You can customize the setters and the getters by overriding the methods and specific some certain conditions for them.
See first answer ( brackets are preferred - better understanding of the code )
Better make a separate method.
Like:
- (void) releaseOutlets {
self.firstOutlet = nil;
self.mySecondOutlet = nil;
……………………
self.myLastOutlet = nil;
}
and then call this method both in viewDidUnload and in dealloc methods.
Hope it helps !
I'm experiencing a weird problem when trying to use an NSManagedObject subclass. I've got code that looks something like this:
[self.navigationController popViewControllerAnimated:NO];
MyController *myController = [[MyController alloc] init];
myController.managedObject = managedObject;
Pretty simple right? But for some reason it crashes in the synthesized function for setting "managedObject". I tried replacing the function with something like this:
- (void) SetManagedObject:(NSManagedObjectSubClass*) obj
{
if ( managedObject )
[managedObject release];
managedObject = obj;
--> [managedObject retain];
}
And that crashes on the retain call... I'm stumped and don't know where to start debugging this.
There are several problems with your code:
If you provide a custom setter, your property is not a synthesized property (remove SetManagedObject: and use the #synthesized directive instead)
Your custom setter is releasing the object before it retains it. So managedObject might have been freed when you send the retain message (That's the crasher)
SetManagedObject: has the wrong case. Use setManagedObject: if you decide to provide a custom setter.
Don't use NS as prefix for your custom subclasses (NS is used by Apple).
I'd use a synthesized property. Remove your setter code, declare #property(retain) XYManagedObjectSubClass managedObject; in your .h file and use #synthesize in the implementation.