Accessing Class Data Members in ViewController.m (xCode / Objective C) - iphone

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

Related

getting EXC_BAD_ACCESS_CODE, objective C

What I am doing is
//ClassB.h
#property (strong, nonatomic) NSString *name;
and
//ClassA.h
#interface ClassA : NSObject
+(ClassA*)methodA:(NSData*)data;
-(id)initWithData:(NSData*)data;
#property (nonatomic, strong) NSMutableArray *arr;
#property (nonatomic, strong) RXMLElement *rxmlRoot;
#end
//ClassA.m
#implementation ClassA
#synthesize arr;
#synthesize rxmlRoot;
+(ClassA*)methodA:(NSData*)data {
return [[ClassA alloc] initWithData:data];
}
-(id)initWithData:(NSData*)data {
self = [super init];
if (self) {
arr = [NSMutableArray array];
rxmlRoot = [RXMLElement elementFromXMLData:data];
/*****edit : just been added to make codes clear*****/
NSString *node = #"players.player";
[rxmlRoot iterate:node with:^(RXMLElement *e){
ClassB *classB = [[[ClassB alloc] init] autorelease];
[classB setName: [e attribute:#"name"]];
// adding ClassB into arr
[arr addObject:classB];
}];
}
return self;
}
#end
So now I am having ClassA object whose arr contains ClassB
Question : later on, when I try to access an particular property of ClassB like
((ClassB*)[classA.arr objectAtIndex:0]).name
and I am getting EXC_BAD_ACCESS at above line..
Please advice me on this issue and how to correct the error. Any comments are welcomed here
Thanks
This line
[arr addObject:ClassB]
makes no sense. Is your intention to put an instance of ClassB into that array, or the class itself (i.e. [ClassB class])? Presumably you must intend to put an instance of ClassB in there, otherwise trying to access its properties later on (e.g. firstName) would make no sense. Also, does your ClassB even have a firstName property, because the piece of ClassB's interface that you show us only mentions a name property.
Update:
Since you are using manual memory management, you need to retain the objects (arr, rxmlRoot) you create in your initializer using convenience constructors, which return autoreleased objects. For example, the code should be
arr = [[NSMutableArray array] retain];
Post your ClassB.m .
Are you making the #synthesize name?
Also make the Alloc for arr.
This line is so wrong:
((ClassB*)[classA.arr objectAtIndex:0]).firstName
Your string is called name , not firstName. It should be :
((ClassB*)[classA.arr objectAtIndex:0]).name
The code in the question has changed substantially, so my previous answer now makes no sense and I have removed it. Given revised code, the first thing to do is to log what's going on.
NSLog(#"classA: %#", classA);
NSLog(#"classA.arr: %#", classA.arr);
((ClassB*)[classA.arr objectAtIndex:0]).name
If it blows up on the first log statement, things are really bad. But then at least you know that classA is pointing to something rotten and you can work back from there.
You can achieve the same thing in the debugger, by setting a break point ahead of the line and inspecting. Given that you are getting an EXC_BAD_ACCESS one of the pointers is pointing to a dodgy object, e.g. one that has been released. It looks as if you are using ARC (because you have strong in your property), which should help manage the memory - but then again, you have an autorelease in there, so maybe not.

Access to variables through delegate

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.

How to share state between viewControllers using the AppDelegate object

I'm trying to share an NSArray object between several different view controllers and my first thought was to add a property on the app delegate as they all have access to this object.
But after some debugging it appears I can't actually share this array for some reason. When I set the object from the first view controller and NSLog the results all is well. But when I attempt to get that array value using another view controller object it always returns UITouchData (not the value previously shown in the logs after my first view controller set the value)
Here is the code that I'm using to set the value
NSArray* cookies = [NSHTTPCookie
cookiesWithResponseHeaderFields:[response allHeaderFields]
forURL:[NSURL URLWithString:#""]];
[appDelegate setAuthCookie:cookies];
Here is part of the .h for my app delegate
#interface SomeAppDelegate : NSObject <UIApplicationDelegate> {
NSArray* authCookie;
}
#property (retain) NSArray* authCookie;
- (void)setAuthCookie:(NSArray *)cookie;
- (NSArray *)getAuthCookie;
#end
Here is the .m for the methods in question
#synthesize authCookie;
- (void)setAuthCookie:(NSArray *)cookie
{
authCookie = cookie;
}
- (NSArray *)getAuthCookie
{
return authCookie;
}
Here is the attempt to grab this array in the second view controller that fails (technically it doesn't fail on this line but I don't get an NSArray back as expected so when I try to use this it fails)
NSArray* cookies = [appDelegate getAuthCookie];
Any way I can share state using the app delegate like this?
Your memory management is wrong, and you are getting a completely different object which has inherited the old array's address when you later use the getter.
Your #property is correct, but you've written your own setter and getter that do not retain the object. You don't need to use both #property/#synthesize and supply your own getter/setter. The former is a newer means of automating the latter.
If you remove your implementations of setAuthCookier: and getAuthCookie then your code should work.

Crash when accessing a NSMutableArray member variable

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.

NSMutableArrays

I have an NSMutableArray as a member variable for a class.
In the .h file:
#interface bleh {
NSMutableArray *list;
}
#property (readonly, assign) NSMutableArray *list;
#end
In the .m file:
#implementation bleh
#synthesize list;
-(void)init;
{
list = [NSMutableArray arrayWithCapacity:30];
}
#end
Now, I'm not really an objective-C programmer, so maybe I'm missing some of the nuances, but when I do the following:
NSMutableString *listItem = [NSMutableString stringWithString:#"Foobar"];
[list addObject:listItem];
I'm getting strange behavior. Namely, I'm using this to keep a list of files that I eventually want to attach to an email and then open the picker. I'm getting a SIGABRT, and upon debugging, I find out that whenever I operate on list, I'm getting nothing. addObject messages don't increase the size of the NSMutableArray at all.
Am I missing something? Can someone show me a full implementation of setting up an NSMutableArray to be manipulated within a class in Objective C?
Thanks.
PS - Assume that I'm smart enough to put the manipulations of the NSMutableArray inside of a member function for the class containing the member variable.
in the latest release of the SDK arrayWithCapacity is bad practice.
but in your code you creating a array that no one is owner , clam your array properly.
don't forget initialize your array
NSMutableArray *array = [[NSMutableArray alloc] init];
fix the (readonly,assign),
How are you actually creating your array? Is it possible that it's being autoreleased and going away? Remember, if you create it with a convenience method (like array or something) you need to retain it.
You're creating the array with arrayWithCapacity:, which returns an array you don't own, and you're never claiming ownership over it. Use a property accessor to retain the array:
self.list = [NSMutableArray arrayWithCapacity:30];
I would recommend reading the Cocoa memory management docs. Once you know the rules in there, it will be clear what to do in this sort of situation. They're not very hard, but they are very necessary if you're going to be programming Cocoa.
Your list variable has been auto-released and de-allocated, therefore your program crashes when you try to access it.
There are two ways to create objects in Cocoa:
NSMutableArray* array1 = [[NSMutableArray alloc] initWithCapacity:10];
NSMutableArray* array2 = [NSMutableArray arrayWithCapacity:10];
array1 was created using alloc+init, therefore you own it. It will stick around until you release it.
array2 was not created using alloc+init, therefore you do not own it. You're not responsible for releasing it, but it will go away on its own. You must retain array2 if you want it to stick around.
Your list property declaration is keeping you from properly retaining the NSMutableArray. By calling arrayWithCapacity you're effectively putting the array in an autorelease pool, which means it could be deallocated at any time if no object interested in keeping it around. While you are, the way you have things declared doesn't reflect that:
#property (readonly, assign) NSMutableArray *list;
The above declaration simply sets this pointer to be a copy of another pointer - it does no memory management for you. Instead it should read:
#property (readonly, retain) NSMutableArray *list;
... and you should assign the list like so:
self.list = [NSMutableArray arrayWithCapacity:64];
Because you specify the retain attribute for the property, whenever it is assigned a new value the retain message will be sent to that new value, communicating to the memory manager that you don't want this object deallocated. In order to bring this full circle, you'll need to release the object when you containing class is deallocated:
- (void)dealloc
{
[list release];
[super dealloc];
}
Are you initializing your list properly? Ie do you have something like the following in your code?
list = [[NSMutableArray alloc] init];
Problem ehre (assuming you initing your array properly) could be that #"Foobar" assings an NSString not an NSMutableString so its failing because if distinct types you should do
NSMutableString *listItem = [NSMutableString stringWithString:#"Foobar"];
[list addObject:listItem];
or
NSString *listItem =#"FooBar";
[list addObject:listItem];
It doesn't look as though you've actually initialized the NSMutableArray.
In the init event of the object, just say
[self setList:[[NSMutableArray alloc] initWithCapacity:10]]];
(I would just say init, but I don't remember if that works. It doesn't matter what capacity you start with)
Before actually allocating the array, the variable "list" will have a value of nil.