What is NSString in struct? - iphone

I've defined a struct and want to assign one of its values to a NSMutableDictionary. When I try, I get a EXC_BAD_ACCESS. Here is the code:
//in .h file
typedef struct {
NSString *valueOne;
NSString *valueTwo;
} myStruct;
myStruct aStruct;
//in .m file
- (void)viewDidLoad {
[super viewDidLoad];
aStruct.valueOne = #"firstValue";
}
//at some later time
[myDictionary setValue:aStruct.valueOne forKey:#"key1"]; //dies here with EXC_BAD_ACCESS
This is the output in debugger console:
(gdb) p aStruct.valueOne
$1 = (NSString *) 0xf41850
Is there a way to tell what the value of aStruct.valueOne is?
Since it is an NSString, why does the dictionary have such a problem with it?
------------- EDIT -------------
This edit is based on some comments below.
The problem appears to be in the struct memory allocation. I have no issues assigning the struct value to the dictionary in viewDidLoad, as mentioned in one of the comments. The problem is that later on, I run into an issue with the struct. Just before the error, I do:
po aStruct.oneValue
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000000
0x9895cedb in objc_msgSend ()
The program being debugged was signaled while in a function called from GDB.
GDB has restored the context to what it was before the call.
To change this behavior use "set unwindonsignal off"
Evaluation of the expression containing the function (_NSPrintForDebugger) will be abandoned.
This occurs just before the EXC_BAD_ACCESS:
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MM-dd-yy_HH-mm-ss-A"];
NSString *date = [formatter stringFromDate:[NSDate date]];
[formatter release];
aStruct.valueOne = date;
So the memory issue is most likely in my releasing of formatter. The date var has no retain. Should I instead be doing
NSString *date = [[formatter stringFromDate:[NSDate date]] retain];
Which does work but then I'm left with a memory leak.

I recreated your code and put the NSDictionary setValue method, right under the aStruct.valueOne = #"firstValue" line. It works perfectly without any error. So, your problem is not with the NSString, but with one of the objects (either aStruct or myDictionary) getting deallocated somewhere down the line. You can try the following:
static myStruct aStruct;
To print the value of aStruct.valueOne, you may use:
NSLog(#"aStruct.valueOne = %# \n", aStruct.valueOne);
Also, you can check the retain counts of myDictionary to see if it is still allocated. However, trying to check for the retain count of an already deallocated object will result in an error. But it will tell you in the error log, that the object is already deallocated.
NSLog(#"Retain Count of myDictionary = %i \n", myDictionary.retainCount);
Hope that helps.

Not sure why it's crashing, but instead of p, use po and it will print the contents of the NSString or description of any NS/CF object.

Try to enable zombies to check where do you over-release objects. Project -> Edit Active Executable -> Arguments tab -> Add variable NSZombieEnabled and assign it YES. (and set checkbox to YES).
Then you should get more info about your error in the trace.
Don't forget to disable NSZombieEnabled checkbox then.
EDIT:
When you assign a valueOne:
aStruct.valueOne = #"firstValue";
you actually create NSString object and put it into autorelease pool. So later when you try to get that object to pass it to your dictionary, it might be autoreleased already, that's why you are getting EXC_BAD_ACCESS. You have to implement some method which will do memory management for you when you assign new pointers to your struct. Something like this:
- (void)setValueOne:(NSString *)newValueOne {
[aStruct.valueOne autorelease];
aStruct.valueOne = [newValueOne retain];
}
So in your viewDidLoad you have to use your new method:
- (void)viewDidLoad {
[super viewDidLoad];
// make sure it is nil "on startup" because setValueOne: method will send autorelease method
aStruct.valueOne = nil;
aStruct.valueTwo = nil;
[self setValueOne:#"firstValue"];
}

Any 'class *instance' is a pointer to an object. That $1 = (NSString *) 0xf41850 you see is actually the pointer to the memory space that is currently allocated to hold valueOne. The issue usually associated with EXEC BAD ACCESS is that the memory space is not permanently allocated to hold valueOne, and is reclaimed later on, usually as soon as the method finishes execution (called garbage collection). Then, when you later try to access it, like from a different method or even the same method but on a subsequent execution, the system says 'hey, that memory address is used for something else", it throws the Exec Bad Access error.
Is there a way to tell what the value
of aStruct.valueOne is?
Well, the debugger, at the moment you establish the value, should be able to pick up on the definition and show you the literal value; it should know that the memory space at 0xf41850 maps to an NSString class, which is an array of bytes of some length, and that the bytes at that address are encoded a certain way, and thus should map into some string that can be displayed on your display in the debugger. However, later on, no, the system has no (valid) idea of what that space contains, since it could contain, well, anything.
So, when you run into EXEC BAD ACCESS, it means that you are not retaining that value for long enough period, either because you have not purposely retained it, or have released it (on purpose or inadvertently let the system release it).

Related

what does #autoreleasepool do?

I am using ARC and i know the autoreleasepool sends release to all elements inside it. Consider the following example.
-(NSString*)someMethod{
NSString *string1=#"sample text inside string 1"; // string1 add to main autorelease pool
NSString *string2=[[NSString alloc] init]; // string2 retain count is 1
string2=#"sample text inside string 2"; // just assigning
return string1;
}
-(void)viewDidLoad{
NSString *returnedString=[self someMethod];
}
1. so my question is how do i completely release string2 in
someMethod?
2. How to completely release string1 from viewDidLoad method completely?
Note: I am using ARC
if i use #autoreleasepool in someMethod then i think it will destroy both string1 and string2. wont it?
And what will be the effect of using #autoreleasepool in someMethod
-(NSString*)someMethod{
#autoreleasepool{
NSString *string1=#"sample text inside string 1"; // string1 add to main autorelease pool
NSString *string2=[[NSString alloc] init]; // string2 retain count is 1
string2=#"sample text inside string 2"; // just assigning
}
return string1;
}
First of all,
NSString *string2=[[NSString alloc] init];
string2=#"sample text inside string 2";
string2 is not an object itself. It is a pointer to an object. So here you create an object, get a pointer to it, and then immediately replace it with a pointer to another string. If you didn't use ARC you would leak memory here. Take a look at #Anoop Vaidya's answer for more details about it.
As for your questions: when you use ARC, the compiler automatically tracks objects and releases them when they are no longer used. So you don't have to release it manually. You could assign a pointer to nil, but as soon as I remember it is not necessary.
The code from your second example won't compile, because string1 is declared inside the autorelease scope. And actually this #autorelease here doesn't make any difference since you don't create autoreleased objects inside it.
This question contains more details about using autorelease pool with ARC.
And Apple's official documentation is probably the best I've ever seen, so please feel free to have a look at their Advanced memory management programming guide. It isn't too long, and it explains everything in details :)
You can't release any object, instance if you are using ARC. It is handled by complier itself when you use ARC.
So, even string will be released the same way.
You don't need to release it ,it will automatically done by ARC.
it will give an error if you try to release any object while using ARC.
NSString *string2=[[NSString alloc] init]; // string2 retain count is 1
string2=#"sample text inside string 2";
Bad way to doing.
Instead do this way
NSString *string2=[[NSString alloc] initWithString:#"sample text inside string 2"];
Or even
NSString *string2=#"sample text inside string 2";
string1 is in autoreleased mode, you dont have to release it.
As you are using ARC(Automatic Reference Counting). You never release object. The compiler takes care of it.

How to release an object in a forin loop?

I'm new to cocoa / objective-c and i'm struggeling with the releases of my objects. I have the following code:
gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
NSString *oid = [gastrocategory objectForKey:#"id"];
GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:#"name"]];
[gastroCategoryList addObject:gc];
}
The analyzer shows me that the "gastrocategory" defined in the for is a potential memory leak. But i'm not sure if i can release this at the end of the for loop?
Also at the following code:
- (NSArray *)eventsForStage:(int)stageId {
NSMutableArray *result = [[NSMutableArray alloc] init];
for (Event *e in eventList) {
if ([e stageId] == stageId) {
[result addObject:e];
}
}
return result;
}
The Analyzer tells me that my "result" is a potential leak. But where should I release this?
Is there also a simple rule to memorize when i should use assign, copy, retain etc. at the #property ?
Another problem:
- (IBAction)showHungryView:(id)sender {
GastroCategoriesView *gastroCategoriesView = [[GastroCategoriesView alloc] initWithNibName:#"GastroCategoriesView" bundle:nil];
[gastroCategoriesView setDataManager:dataManager];
UIView *currentView = [self view];
UIView *window = [currentView superview];
UIView *gastroView = [gastroCategoriesView view];
[window addSubview:gastroView];
CGRect pageFrame = currentView.frame;
CGFloat pageWidth = pageFrame.size.width;
gastroView.frame = CGRectOffset(pageFrame,pageWidth,0);
[UIView beginAnimations:nil context:NULL];
currentView.frame = CGRectOffset(pageFrame,-pageWidth,0);
gastroView.frame = pageFrame;
[UIView commitAnimations];
//[gastroCategoriesView release];
}
I don't get it, the "gastroCategoriesView" is a potential leak. I tried to release it at the end or with autorelease but neither works fine. Everytime I call the method my app is terminating. Thank you very much again!
In your loop, release each gc after adding it to the list since you won't need it in your loop scope anymore:
gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
NSString *oid = [gastrocategory objectForKey:#"id"];
GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:#"name"]];
[gastroCategoryList addObject:gc];
[gc release];
}
In your method, declare result to be autoreleased to absolve ownership of it from your method:
NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease];
// An alternative to the above, produces an empty autoreleased array
NSMutableArray *result = [NSMutableArray array];
EDIT: in your third issue, you can't release your view controller because its view is being used by the window. Setting it to autorelease also causes the same fate, only delayed.
You'll have to retain your GastroCategoriesView controller somewhere, e.g. in an instance variable of your app delegate.
BoltClock's answer is spot-on as to the first part of your question. I'll try to tackle the rest.
Assign is for simple, non-object types such as int, double, or struct. It generates a setter that does a plain old assignment, as in "foo = newFoo". Copy & retain will, as their names imply, either make a copy of the new value ("foo = [newFoo copy]") or retain it ("foo = [newFoo retain]"). In both cases, the setter will release the old value as appropriate.
So the question is, when to copy and when to retain. The answer is... it depends. How does your class use the new value? Will your class break if some other code modifies the incoming object? Say, for example, you have an NSString* property imaginatively named "theString." Other code can assign an NSMutableString instance to theString - that's legal, because it's an NSString subclass. But that other code might also keep its own reference to the mutable string object, and change its value - is your code prepared to deal with that possibility? If not, it should make its own copy, which the other code can't change.
On the other hand, if your own code makes no assumptions about whether theString might have been changed, and works just as well whether or not it was, then you'd save memory by retaining the incoming object instead of unnecessarily making a copy of it.
Basically, the rule, which is unfortunately not so simple sometimes, is to think carefully about whether your own code needs its own private copy, or can correctly deal with a shared object whose value might be changed by other code.
The reason you can release gc after it is added to the gastroCategoryList is that when an object is added to an array, the array retains that object. So, even though you release your gc, it will still be around; retained by the gastroCategoryList.
When you are returning a newly created object from a method, you need to call autorelease. This will cause the object to be released only after the runtime leaves the scope of the calling method, thereby giving the calling method a chance to do something with the returned value.
Note that if your method starts with the word copy or new, then you should not autorelease your object; you should leave it for the calling method to release.
As for copy vs retain vs assign... as a general rule, copy objects that have a mutable version, such as NSArray, NSSet, NSDictionary, and NSString. This will ensure that the object you have a pointer to is not mutable when you don't want it to be.
Otherwise, use retain whenever you want your class to be ensured that an object is still in memory. This will apply to almost every object except for objects that are considered parents of your object, in which case you would use assign. (See the section on retain cycles here).
Also note that you have to use assign for non-object types such as int.
Read through the Memory Management Programming Guide a bit; it's quite helpful.

instance variables not accessible

Serious Problem here... i'm getting ECX_BAD_ACCESS if i try to NSLog an instance variable of my custom object. Following Function is called in my ViewController, payload holds String Data which is pulled from a url.
- (void) initVcardWithData:(NSString *)payload {
NSLog(#"1. initVcardWithData");
aVCard = [[vcardItem alloc] initWithPayload:payload];
VCardViewController *aVCardViewController = [[VCardViewController alloc] initWithVCard:aVCard];
[self presentModalViewController:aVCardViewController animated:YES];
[aVCard release];
}
So far so good. The initWithWithVCard function is as follows, theVCard and theVCardN are defined in #implementation and also set as a #property (nonatomic, retain) in (.h).:
-(id)initWithVCard:(vcardItem *)aVCard {
if(self = [super init]) {
theVCard = [aVCard retain];
theVCardN = [theVCard.PersonName retain];
}
NSLog(#"---- vCardViewController :: initWithVcard :: FirstName: %#", theVCard.PersonName.FirstName);
return self;
}
If i access the theVCardN object in my ViewController aVCardViewController within ViewDidLoad everything works like a charm. I set some labels with data from that object.
If i then try to access the instance variables from theVCardN within a function which is called from an IBAction which is connected to a button in View, i get an EXC_BAD_ACCESS error at the debugger console. The Function which tries to pull data from the instance variables is as follows:
-(IBAction)addressbookButtonTapped {
NSLog(#"RETAIN COUNT FOR theVCard: %i", [theVCard retainCount]);
NSLog(#"RETAIN COUNT FOR theVCardN: %i", [theVCardN retainCount]);
NSLog(#"Save to Adressbook: %#", theVCardN.FirstName);
//[self dismissModalViewControllerAnimated:YES];
}
The RetainCounter for theVCardN right before calling NSLog outputs "1". The NSLog Line then returns EXC_BAD_ACCESS in Debugger Console.
Any idea ?
Do not call -retainCount. Absolute retain counts are useless.
retainCount returns the absolute retain count of an object. The actual value will be an implementation detail that is very often completely out of your control as the system frameworks may do any number of things internally to cause the retain count to be modified in ways you don't expect.
It is useless for debugging and their are a wealth of tools that are specifically focused on tracking down these kinds of issues.
First, if there is a crash, there is a backtrace. Post it. Probably not that interesting in this case, but, still, always look to the backtrace to at least confirm that it is crashing where/how you think it is.
From the evidence posted, it sounds like theVCardN.FirstName is either set to garbage or the underlying string has been over-released. Turn on zombie detection mode and see if that is the case. Since it is crashing on FirstName, then show the code related to creating/storing the FirstName.
Also, instance variables and methods should always start with a lowercase letter; PersonName should be personName & FirstName should be firstName.
Maybe i'm reading the code wrong or misunderstanding your class structure, but it looks like you logging:
NSLog(#"Save to Adressbook: %#", theVCardN.FirstName);
Above, where you say it is still working, you are logging:
theVCard.PersonName.FirstName
Are you missing the "PersonName"? Meaning you should be logging:
NSLog(#"Save to Adressbook: %#", theVCardN.PersonName.FirstName);

Objective-C iPhone - NSMutableArray addobject becomes immediately out of scope

ok. I have a really odd and mind boggling problem. I have two class files, both of which are NSObject inheritors. The series of code is as follows
CustomClass *obj;
obj = [[CustomClass alloc] init];
[myArray addObject:obj]; <--------Immediately after this line if I hover over the array it shows it as having 1 object that is out of scope.
If I hover over both objects they both have what look to be initialized memory locations so I really have no idea what is going on here. Thanks in advance.
UPDATE: There is a place in the code where I call a function repeatedly with a timer. Inside of the timer I do the following.
CustomClass *obj = [CustomClass alloc];
obj = [myArray objectAtIndex:0];
obj.var += 10;
[obj release];
On the line obj.var I get a EXC_BAD_ACCESS error. I am probably doing the alloc and releases incorrectly considering it is called repeatedly but I have tried everything I can think of.
I think you are referring to the XCode debugging feature which shows you the content of variables.
I did encounter the same issue as well, and what I'm sure of is that this is generally not a problem with your code.
Now what I'm not sure of is why this happens, but I believe that the variable obj in your example is not used after the call anymore. This means the compiler reuses the place where this reference was stored, thus the debugger could "lose" the pointer to your variable and it will appear as out of scope (but I am no expert in the ways of gcc or the debugger, so I could be wrong here).
This code is wrong:
CustomClass *obj = [CustomClass alloc];
obj = [myArray objectAtIndex:0];
obj.var += 10; [obj release];
What you are doing is allocing a new CustomClass (without initializing it, which should never be done), then replacing it with the object from the array (leaking the old one), and then afterwards releasing the object from the array. This will cause a crash the next time the object in the array is accessed. Instead, just say:
CustomClass *obj = [myArray objectAtIndex:0];
obj.var += 10;
Don't release unless you retain in advance. (See the Cocoa memory management guide for more information).
This isn't the problem you are referring to, but please don't do this:
CustomClass *obj = [CustomClass alloc];
Never issue an alloc without an init of some sort. Also, in the context of the code you posted it isn't required, as you assign a value to obj on the next line.
Then [obj release]; isn't required, as you haven't retained the obj value you obtain from myArray. You are probably doing it because of the preceding alloc, which as I have said isn't required.
if a reference to obj.var is causing a BAD_ACCESS, then either obj or var has been dealloced by code elsewhere, almost certainly var.

NSMutableArray gets corrupted

I'm doing an iPhone application which uses a navigation control to browse through some data. This data is stored in a sqlite database and I have a class which gets it and returns it in a NSMutableArray of NSStrings.
The problem is that in the first screen of the navigation everything works prefectly, but in the second screen (another view which is pushed) the same code fails because the NSMutableArray gets corrupted. In the debugger I can see that it is returned correctly, but when it's time to use it the pointers have become corrupted and the application crashes.
I have put breakpoints in all my functions, and I can't see anywhere where it can get corrupted. And as the first view, which uses the same exact code, even accesing the same eact tables, works correctly I don't really know where to look.
If anyone want to have a look at the code I have uploaded it to my site: http://sachafuentes.com/iBacus.zip
Thanks in advance.
UPDATE:
The problem lies in the function where I get the data, which looks like (this is a simplified version with some pseudo-code).
-(NSMutableArray *) getPaises {
NSMutableArray * paises;
paises = [[NSMutableArray alloc] init];
while( get new row ) {
NSString *aPais = get the value;
[paises addObject:aPais];
[aPais release];
}
return paises;
}
If I comment out [aPais release] everything works, but to me this looks like a memory leak, as the NSString won't be released.
Okay, here's the problem:
NSString *aPais = [NSString stringWithUTF8String:(char*)sqlite3_column_text(compiledStatement, 0)];
By convention, any time that you see an alloc and an init, you need a release somewhere down the road.
By convention, any time that you use an xWithX: style method, the resulting object will be released for you.
Therefore, this statement:
[aPais release];
will cause your method to crash, as the object is released before it should be. Just remove this line, set your NSMutableArray instance to be autorelease-d and you should get better results.
Look for wrong memory management, that's the likeliest cause for crashes. I think you release your objects somewhere where you shouldn't and therefore you have dangling pointers in the array.
Update1
[aPais release] is wrong, as you don't retain it anywhere in this method. Returned values should always be autoreleased. You should have the same amount of retain as release in your code.
(Some people argue that a retain can also be an alloc init, but I always try to use alloc init autorelease, but this is a matter of style.)
BTW
You should autorelease your array, you're only retaining it here with [[alloc] init].
Any object that you alloc and init must be release-d when you're finished with it, or you will have a memory leak.
Since you are passing the reference outside the scope of the getPaises method, you must autorelease the NSMutableArray, or you will have a memory leak:
paises = [[[NSMutableArray alloc] init] autorelease];
Can you please clarify the step here:
NSString *aPais = get the value;
It's not clear what happens in "get the value" and I suspect this is one cause of instability.
I see that the code is (verbatim)
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
NSString *aPais = [NSString stringWithUTF8String:
(char*)sqlite3_column_text(compiledStatement, 0)];
[paises addObject:aPais];
[aPais release];
}
...and it's exactly as #gs puts it. aPais is autoreleased and should not be released.
You can also use a convenience constructor to initialize the NSMutableArray:
NSMutableArray *paises = [NSMutableArray array];
This is equivalent to doing:
NSMutableArray *paises = [[[NSMutableArray alloc] init] autorelease];