in my app I am trying to run some code that currently exists in my applicationWillTerminate in appDelegate.
I have c/p'd the same code into the method that is currently running (verified by NSLog), but the code just doesnt seem to execute the same way.
The following code is from my applicationWillTerminate, which saves data, ready for loading next time.
[myArray makeObjectsPerformSelector:#selector(saveAllDataLeads)];
when I insert this into my DetailViewController.m (in a method that is currently active), I insert the following.
[appDelegate.myArray makeObjectsPerformSelector:#selector(saveAllDataLeads)];
The problem is that it just doesn't do the stuff in saveAllDataLeads, can someone see what is wrong? or is more information required.
Regards
in DetailViewController.h i have declared
MyAppDelegate *appDelegate;
The objects that you have added to myArray must have a selector with no parameters, named saveAllDataLeads, that is:
#interface MyObject : NSObject {
}
- (void)saveAllDataLeads;
#end
#implementation MyObject
- (void)saveAllDataLeads {
// do something
}
#end
Then, presumably somewhere you are adding instances of MyObject to myArray:
MyObject* instance = [MyObject new];
[appDelegate.myArray addObject:instance];
[instance release];
Related
I am relatively new to Objective-C, about 1 year experience, and I had encountered an issue with trying to add a class to my project. When I add a class of UIViewController subclass, with XIB file included, I have no problems with that at all, xcode is working very well that way.
However, I tried to add a simple Objective-C class to the project called Test, with the following .h and .m files, and had a problem where the code compiles and builds without error but the method TestMethod always returns nil. What might be wrong here?
Test.h
#import <Foundation/Foundation.h>
#class Test;
#interface Test : NSObject {
}
- (NSString *)TestMethod;
#end
Test.m
#import "Test.h"
#implementation Test
- (NSString*)TestMethod {
return #"Test";
}
#end
In my UIViewController subclass with XIB file, that subclass works without error, but when I try to include my Test class in it, the method TestMethod returns nothing, even though it is hardcoded to always return the same string:
#import "Test.h"
Test *testobject;
// this compiles and builds but returns nothing
NSString *testString = [testobject TestMethod];
You missed to alloc + init.
Use
Test *testobject=[[Test alloc] init];
or
Test *testobject=[Test new];
Whenever your object is un-initialised you will get nil value.
EDIT:
In ARC : it's default initialized .
In MRC : the value could be uninitialized (garbage value).
TestMethod isn't returing nil - testobject is nil.
Change
Test *testobject;
to
Test *testobject = [[Test alloc] init];
You have not created an instance of Test, so testObject just holds nil. You need to assign an instance of Test to the variable in order to do what you want.
You can also take this approach
//Test.h
#import <Foundation/Foundation.h>
#class Test;
#interface Test : NSObject {
}
- (id)init;
-(NSString*)TestMethod;
#end
Now in your Test.m file
//Test.m
#import "Test.h"
#implementation Test
- (id)init {
if (self=[super init]) {
}
return self;
}
-(NSString*)TestMethod {
return #"Test";
}
#end
Now if you want to call this Test Class in another class, you have to create an instance of Test Class.
Test *testobject = [[Test alloc] init];
NSString *testString = [testobject TestMethod];
To access any method/property of a class, first you need to allocate memory to object of that class using alloc/new method.
Since you created variable of that class type <Test *testobject>. But variable does not allocated any memory, by default it will be nil. Using "nil" you can call any method in objective C. It will not crash. But it will return nil.
So, Before accessing any object you must created memory for that object
Test *testobject = [Test alloc];
initialized the object with default constructor (init, initWith, etc...)
[testobject init];
Now object is ready for calling instance method/setter/getter etc...
NSString *testString = [testobject TestMethod];
I've go a situatiion in Objective-C where I'm trying to access an object's variable through another object. The classes (simplified):
A.h
#interface A : NSObject {
NSMutableArray *someStuff;
}
#property (nonatomic, retain) NSMutableArray *someStuff;
#end
A.m
#implementation A
#synthesize someStuff;
// blah, blah, blah
Then, because I'm doing an iPhone app, there is an app delegate that contains a variable of this object type:
AppDelegate.h
#interface AppDelegate : NSObject <UIApplicationDelegate> {
A *aPtr;
}
#property (nonatomic, retain) A *aPtr;
#end
AppDelegate.m
#implementation AppDelegate
#synthesize aPtr;
// blah, blah, blah
Then, in another class (in this a view controller), I'm trying to access 'someStuff' in this manner:
AViewController.m
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSMutableArray *someArray = appDelegate.aPtr.someStuff;
So, the problem is that this blows up in fine fashion. I think I'm too much of a Java junkie to understand why this won't work. Can anyone elighten me?
Many thanks,
Craig
You need to initialize this in this way
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
NSMutableArray *someArray = appDelegate.someArray;
This will resolve your problem.....
Craig,
appDelegate.aPtr will return null. as it is not initialized yet, and when you try to access some member of a null object,(in java NULLPointerException).Its behavior is as expected.(this blows up in fine fashion).
Thanks,
Ravin is correct. The class definition defines the iVars and properties for a class so you have defined an iVar aPtr that references an object of type A. However, you have not allocated and initialized this object.
An example using the default initialization would be `aPtr = [[A alloc] init]'.
This all sounds suspicious since in ObjC you are allowed to send messages to nil without a problem and properties are just diguised methods. For example you can
view = nil;
view.hidden = NO;
and it doesn't blow up, it just does nothing.
So since appDelegate.aPtr.someStuff is just
[[appDelegate aPtr] someStuff];
and [appDelegate aPtr] does nothing and returns nil so it should be safe to call [[appDelegate aPtr] someStuff] without a problem but also without any results.
So while it is a problem with using objects that hadn't been initialized (which most often should be done in a designated constructor of the appropriate object), since you don't get results that you expect, in my undestanding of "sending message to nil" in ObjC it shouldn't blow up. If it is then either I am missing the point or something other causes the problem and not this call.
EDIT
just checked: if not initialized at all it works as I explained: ObjC allows messages to be sent to nil:
A *aPtr = appDelegate.aPtr;
NSMutableArray *someArray = aPtr.someStuff;
NSLog(#"%#", someArray);
or
NSMutableArray *someArray = appDelegate.aPtr.someStuff;
NSLog(#"%#", someArray);
both don't break and print null.
If you initialize A properly but not initialize someStuff in A it still doesn't break but print null. The problem might be that you initialize aPtr to a different class than A, in which case you get unrecognized selector exception (you should be able to see it in the error log) and program crash.
I have a class myClass and would like to access its properties, a NSArray *currentOptions (specifically to get the size of currentOptions and access the NSStrings which I've put in it.)
I have a method called generate options which assigns an filled array to *currentOptions. Generate options is called before I try to access *currentOptions. An instance of myClass has also been added to the ViewController via the App delegate. However when buttonOnePressed is called, I keep getting this error:
[myClass currentOptions]: unrecognized selector sent to instance 0x9b10490
Here is the parts of my code:
//TClass.h
#interface TClass : NSObject {
NSArray *currentOptions;
}
#property (nonatomic, retain) NSArray *currentOptions;
#end
//viewController
- (IBAction) buttonOnePressed:(id)sender {
NSLog(#"button1 pressed");
NSLog(#"int: %d",[myClass.currentOptions count]);
//myClass here is the instance of TClass
}
One thing that sometimes causes that error is failing to properly retain myClass. (Aside: "myClass" is a really bad name for a pointer because the thing being pointed to is almost certainly not a class but an object, i.e. an instance of a class.) If you don't retain the object that myClass points to, it will be deallocated. Sometimes, a different object happens to be created at that some location, and you end up sending a message meant for the original object to the new one, which is a different type and doesn't understand the message.
To all who have been following, the problem has been resolved by making the following changes:
1) Synthesized current options TClass.m
#implementation TClass
#synthesize currentOptions;
#end
2) I made currentOptions a NSMutableArray instead of a NSArray. This is because I need to reassign values to current options. Somehow it crashes with NSArray and everything goes smoothly with NSMutable array like such
#implementation TutorialClass
if ([currentOptions count] > 0) {
[currentOptions removeAllObjects];
}
[currentOptions addObject:[options objectAtIndex:0]];
[currentOptions addObject:[options objectAtIndex:1]];
[currentOptions addObject:[options objectAtIndex:2]];
[currentOptions addObject:[options objectAtIndex:3]];
3) And of course, I'll also have to do the following in the init method of TClass.m
currentOptions = [[NSMutableArray alloc] init];
Now its time to get some food. Thanks Caleb :D
I'm having some trouble with a NSMutableArray. I'm sure i'm doing something wrong with the allocation of the NSMutableArray but it's not obvious to me being an iPhone newbie. When i run the code below i can add the object MyObject to the array objects_ and set the name etc. The NSLog displays the correct data.
But when i try to access the objects_ member from the function printObject i get a SIGABRT. Looks like the memory has been deallocated or something?
Any help appreciated.
#interface MyObject : NSObject {
NSString *name;
}
-(void) SetName:(NSString*) name_str;
-(NSString*) GetName;
#end
#interface ObjectListViewController : UITableViewController {
NSMutableArray* objects_;
}
-(void) initTableData;
#end
#implementation ObjectListViewController
- (void)initTableData {
objects_ = [[NSMutableArray alloc] initWithCapacity:10];
MyObject *obj = [MyObject alloc];
[obj SetName:#"Test"];
[objects_ addObject:obj];
MyObject* testObj = (MyObject*)[objects_ objectAtIndex:0];
NSLog([testObj GetName]);
}
- (void)printObject {
MyObject* testObj = (MyObject*)[objects_ objectAtIndex:0];
NSLog([testObj GetName]);
}
We can eliminate the lack of an init call on MyObject as the cause of the crash as in this case it will be benign. Calling init on NSObject will just return self, so calling it in this case won't change the behaviour. So I don't think the first two answers here will make any difference:
An object isn’t ready to be used until it has been initialized. The init method defined in the NSObject class does no initialization; it simply returns self.
Chuck correctly points out that init is a fundamental step in object allocation and initialization and you should be calling it when you allocate MyObject.
I am not sure the third answer is correct either. I don't really see how adding synthesise on the objects_ array will make any difference. You haven't defined it as a property, and I don't really see why you would need to, given it is just data internal to the class.
The comment on the question Well, for starters, you never define printObject in the #interface. from eykanal doesn't really help you either, because you must be calling printObject internally, otherwise you wouldn't be hitting the crash.
Reading the through the code, I can't see an obvious error. The retain count on objects_ after initTableData finishes should be one, the retain count on the instance of MyObject should also be one. So I think there must be some other code that is releasing objects_ elsewhere?
I am assuming it is crashing on the objectAtIndex call? Is there any info in the console? What does the call stack look like?
MyObject *obj = [MyObject alloc];
should be:
MyObject *obj = [[MyObject alloc] init];
#interface ObjectListViewController : UITableViewController {
NSMutableArray* objects_;
}
#property (nonatomic, retain) NSMutableArray *objects_;
-(void) initTableData;
-(void) printObject;
#end
add the synthesize in the implementation
#implementation ObjectListViewController
#synthesize objects_;
Here are some issues in your code:
You never initialise your MyObj object. Although it inherits directly from NSObject and NSObject is documented to do nothing except return self, you never know if other stuff happens behind the scenes, so put it in just to eliminate the posssibility.
Your methods don't follow the normal naming conventions. method names should begin with a lower case letter and "get" should only be used when passing back data by reference through the parameters as in e.g. NSData -getBytes:length:. Your getter and setter should be -name and -setName: respectively. This may seem like a minor nitpick, but it'll help you later on if you start to use KVO and KVC.
Never do NSLog(someStringVariable) always NSLog(#"%#", someStringVariable). As you have it now, if the object's name contains a percent formatting sequence e.g. %#, %d, %s etc, your program will crash on the NSLog. However, this is not the cause of your current problem - it would be crashing on the NSLog in -initTableData
you don't need to cast the result of -objectAtIndex:
Having said all that, I can't see anything that would cause the particular issue you have. It may be that the getter or setter for the name in MyObject is incorrect. Please post them.
Is there a reason, other than as may be required by object scope across different methods of the object, to use an object like this:
#interface
...
ViewMgmtAppDelegate : NSObject <UIApplicationDelegate> {
Obj *obj1;
...
}
#end
#implementation
- (void)applicationDidFinishLaunching:(UIApplication *)application {
obj1 = [Obj alloc];
[window addSubview:obj1];
...
}
- (void)dealloc {
[obj1 release];
...
}
#end
Instead of this:
#interface
...
ViewMgmtAppDelegate : NSObject <UIApplicationDelegate> {
...
}
#end
#implementation
- (void)applicationDidFinishLaunching:(UIApplication *)application {
Obj obj1 = [Obj alloc];
[window addSubview:obj1];
[obj1 release];
...
}
- (void)dealloc {
...
}
#end
Is either way more efficient?
Any help appreciated // :)
I assume you are asking if you should release the object right after addSubview or in dealloc.
It depends on the application logic and what addSubview does. If addSubview retains the object you can release it right after the call if you don't need it in your other object.
When window is done with it and it releases the object which will get deallocated if no other object holds reference to it.
If on the other hand you keep the reference until your object is deallocated then the object will hang around until your object is deallocated.
If you don't need it then release right away.
By the way the correct way to create and instance is to call:
Obj * o = [[Object alloc] init]
Alloc allocates memory, init (or any other init... methods) initializes the object (I believe).
You would use your first example in case that your obj1 will be used after the view finished loading. For example after a click event.
The second example will be used if this is not the case. So Obj1 is not needed anymore after the release and does not need to use the RAM of the iPhone.
If the object is only used by that method, then it should be a local variable and released in that method (as in the second example). If it's a property of the class that other methods use, it should be stored in an instance variable and released when the owning object goes away (as in the first example).