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);
Related
- (void)viewDidLoad
{
[super viewDidLoad];
[VenueManager searchNear:#"Orlando"
onLoad:^(NSArray *objects) {
self.locationObjects = objects;
[self.tableView reloadData];
} onError:^(NSError *error) {
NSLog(#"%#", error);
}];
}
This code is in my viewDidLoad method of my UITableViewController class. It is the starting point for using RestKit to parse a JSON file from FourSquare. I was pulling my hair out because i couldn't get the objects to show up in my Table View until i put [self.tableView reloadData];. With out that call the app never even hit my - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *) because after the block was done executing locationObjects would be nil.
Before when I was debugging it the self.locationsObjects = objects worked when i was in the block (i am very unfamiliar with blocks by the way). As soon as i was out of the block the debugger would say locationObjects was nil, even though it had said it had 30 objects just like objects did when i had a break point at the assignment statement.
Can some one help me understand what is going on here.
Additional info:
Right now everything is working, or appears to be working my table is populated with the objects request from the JSON document. Originally I was doing this exact same thing in a normal ViewController and trying to set the objects from the block equal to locationObjects. Then using a prepareForSegue method i was trying to pass the locationObjects to the tableViewController in the standard method i have learned from numerous tutorials. I would get a SIGBAT error. The thread would terminate because of an unrecognized selector sent to the table view controller. Through debugging i would find that locationObjects could be nil in the prepareForSegue method. Here is the code from the viewController file.
Also I would get a warning here locationTableViewController.locationObjects = self.locationObjects; saying something about assigning a pointer of type NSArray to strong NSArray, or something like that ( i have since changed a lot attempting to get the code working and deleted some storyboard assets, so i'm not 100% sure of the wording).
#implementation CoffeeShopViewController
#synthesize venueCountLable = _venueCountLable;
#synthesize locationObjects = _locationObjects;
- (void)viewDidLoad
{
[super viewDidLoad];
[VenueManager searchNear:#"Orlando"
onLoad:^(NSArray *objects) {
self.venueCountLable.text = [NSString stringWithFormat:#"%d", objects.count];
self.locationObjects = objects;
} onError:^(NSError *error) {
NSLog(#"%#", error);
}];
}
- (void)viewDidUnload
{
[self setVenueCountLable:nil];
[super viewDidUnload];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"locationTableSegue"])
{
LocationTableViewController *locationTableViewController = segue.destinationViewController;
locationTableViewController.locationObjects = self.locationObjects;
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#end
Try:
#property (nonatomic, copy) NSArray *locationObjects;'
Edit on why this works:
To be honest, I really don't know the underlying reason for this to work and strong not working.
When I saw the problem, it appeared to me that strong being equivalent of retain - inserting copy instead of strong could secure that locationObjects wouldn't be nullified. Thinking again over it, I suspected that my assumption could be wrong - retain literally meant 'Do not release this object because now there is one more guy holding it.'
That, however, works somewhat differently. See this.
What Malaxeur's answer and comments below tells could possibly apply to NSArray in your example - despite strong ownership to locationObjects, what you are given is a reference to objects NSArray (an NSMutableArray*) instead of copy of it. Once out of scope (block end), it is no longer usable, and ARC claims it. Using copy in turn forces it to create another space in memory just for locationObjects, which would remain forever until you free it up.
I still do not consider this a perfect explanation as I have never understood blocks fully. I would keep this open to everyone who knows better, would fill up as soon as I get something that's useful.
So here is my code:
-(void)setMovie:(NSURL *)movieLocal {
movie = movieLocal;
[self.movie retain];
...
}
And i get this error:
Potential leak of an object allocated on line 43
Line 43 is [self.movie retain];. Am i doing something wrong, and how can i get rid of this error?
There are a couple issues here:
The old value for movie is never released
'movie' and 'movieLocal' might point to the exact same object. If that is the case, you will call retain on movie/movieLocal without a subsequent balanced release call.
You might want to use the following:
-(void)setMovie:(NSURL *)movieLocal {
if (movie == movieLocal) {
return;
}
[movie release];
movie = [movieLocal retain];
//...
}
Here's the proper setter:
-(void)setMovie:(NSURL *)movieLocal {
if (movie != movieLocal) {
[movie release];
movie = movieLocal;
[movie retain];
}
}
However, if you declared your property (in .h file):
#propert (nonatomic, retain) NSURL *movie;
and synthesized it in .m file, by #synthesize movie;, than there is no need to explicitly override the setter - the code above will be generated automatically for you. So whenever you want to set your movie you'll just call self.movie = newMovie; which will be equivalent to calling [self setMovie:newMovie];.
For more info read a section "Declared Properties" in Learning Objective-C guide.
EDIT: to explain what was wrong with your setter.
-(void)setMovie:(NSURL *)movieLocal {
movie = movieLocal; // first line
[self.movie retain]; // second line
...
}
In 1st line you are assigning movie to point to movieLocal, but you don't release old NSURL object that movie was pointing to before assignment. This was way, your causing a memory leak - you abandon memory, so it can never be relinquished back by your app. In general, abandoning memory is an easy way to get you application terminated by iOS, when objects are big and often leaked.
In 2nd line you are calling you setMovie setter again as self.movie = syntax causes the runtime to call a setter for movie property. This time it'll cause an infinite loop.
I hope my wording was clear for you and my answer helpful.
i have some trouble writing a method in Objective-C to make an object nil. Here is some example :
#interface testA : NSObject
{
NSString *a;
}
#property (nonatomic, retain) NSString *a;
+(testA*)initWithA:(NSString *)aString;
-(void)displayA;
-(void)nillify;
#end
#implementation testA
#synthesize a;
+(testA*)initWithA:(NSString *)aString{
testA *tst=[[testA alloc] init];
tst.a=aString;
return [tst autorelease];
}
-(void)displayA{
NSLog(#"%#",self.a);
}
-(void)nillify{
self=nil;
}
- (void)dealloc {
[a release];
[super dealloc];
}
#end
int main(int argc, char **argv){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
testA *test=[testA initWithA:#"some test"];
[test displayA];
test=nil;
//[test nillify];
NSLog(#"after setting to nil");
[test displayA];
[pool release];
return 0;
}
Apparently , when I set test object to nil and then call some method on it nothing happens , but if i call nillify instead of directly setting it to nil , displayA method works normally like test object is still there. Is there a workaround for nillify method to function properly ?
Your help is much appreciated !
You can't actually do something like this, because setting 'self' to nil only has any effect within the scope of that method (in your case, 'nilify'). You don't have any actual way to effect the values of pointers located on other parts of the stack or in random places in the heap, for example.
Basically any code that holds a reference to some object is responsible for maintaining and clearing those references itself. If you have some use case where random sections of code may need references to "live" objects of some kind, but where you'd want those object references to go away in response to some external event (maybe a user tracking system or something), you could do something with notifications, but the various modules tracking those "live" objects would still be responsible for listening for notifications and cleaning up references when they received them.
The 'nilify' thing, however, can't possibly work.
You cannot do what you're trying to do. self is just a local reference to an object that actually exists elsewhere. Setting it to nil doesn't mean anything. An object doesn't, in general, own itself, and it certainly doesn't control other objects' references to it. It's up to the owning objects to manage its lifetime.
There are a few things wrong with your code.
First, by convention, class names start with an uppercase letter. Please stick to these naming conventions as it will make it harder for other developers to work with your code (and even confuse you).
Next, your initWithName:... According to the naming conventions, a method with init in its name should be an instance method, not a class method. So either name it newWithName: or turn it into an instance method like this:
-(testA*)initWithA:(NSString *)aString{
self = [super init];
if (!self) return nil;
tst.a=aString;
return self;
}
If you keep it as class method (and name it newWithName:) you should not return a autoreleased object since according to the naming conventions method that start with init... or new... return a retained object. If you do not follow these conventions, the static analyzer will give you "false" warnings and it will become useless for you.
Now for the reason your nillify doesn't work: the self is in fact an argument to a method. Under the hood, your nillify method actually has two arguments that you do not see: the self pointer and the selector pointer. This means, self is actually a variable on the stack. And if you overwrite it, you only overwrite that stack variable but that doesn't influence your test variable which is somewhere else.
As an example, consider a method - (void)foo:(NSString *)bar;. The compiler turns it into the equivalent of the C function (void) foo(id self, SEL _cmd, NSString *bar).
I'm constructing a small iphone app and using a singleton to store and update a string that gets updated when the user taps letters or numbers on the screen to form a code.
i.e. they tap 3 then S then 4 and I need to track and combine that input to give me "3S4" say. When the singleton is initialised it creates an empty NSString and I then use the stringByAppendString method to add on the next letter/number tapped. When I first tried this I did not have the [enteredCode retain] line in there and the app would crash with EXC_BAD_ACCESS, always after 2 inputs. I set the NSZombie property which told me that the enteredCode had been de-allocated but I don't know where or how that happened. All I know is that at the end of the addInput method it will report the retainCount to be 2 say and then straight after I can see (by calling the singleton from elsewhere) it will drop down to 1 (when the retain line is in there).
My question is: though what I've done by adding [enteredCode retain] works for me am I breaking some rules here or going about this in the wrong/bad way? I just can't see why the string is being released.
I'm new to Objective-C btw
in MySingleton.h
#interface MySingleton : NSObject {
NSString *enteredCode;
}
in MySingleton.m
-(void) addInput:(NSString *) input
{
NSLog(#"enteredCode retain count is : %d \n ",[enteredCode retainCount]);
enteredCode = [enteredCode stringByAppendingString:input];
NSLog(#"enteredCode retain count is : %d \n ",[enteredCode retainCount]);
[enteredCode retain]; // without this the app crashes
NSLog(#"enteredCode retain count is : %d \n ",[enteredCode retainCount]);
}
-(id) init
{
self = [super init];
if (self)
{
enteredCode = #"";
}
return self;
}
First, never use the -retainCount method. The absolute count of retains on an object is an implementation detail of the frameworks and will often return confusing results.
Retain counts are something you should maintain entirely as a balanced set of deltas. If you cause a retain count to be added to something, you must release or autorelease that object somewhere. End of story.
This document explains it all.
With that knowledge in hand, the source of your crash is a fairly common memory management mistake.
enteredCode = [enteredCode stringByAppendingString:input];
Every time that line of code is executed, you are replacing enteredCode with an autoreleased instance of NSString. The autorelease pool is drained and your program crashes the next time enteredCode is used.
Your solution of retaining enteredCode is only half the solution. You need to ensure that the original value of enteredCode is released, too. See the memory management docs.
If this were my app, I would turn enteredCode into an #property that copies the string and always set and access enteredCode through that property, never retaining or releasing it manually in my code (outside of -dealloc, of course).
NSString's stringByAppendingString: returns a new NSString made by appending one string to the other, and the new NSString is set to autorelease, which empties the autorelease pool and your next run crashes the app. You're redefining an existing string with stringByAppendingString:, and that's causing the retain problems. (Alternatively, use NSMutableString and you can avoid this.)
By the way, you can do if (self = [super init]) in your init override. The declaration returns true if it occurs or can occur.
Here's how your code should look:
#interface MySingleton : NSObject {
NSString *enteredCode;
}
#property (nonatomic, retain) NSString *enteredCode;
#end
#synthesize enteredCode;
-(void) addInput:(NSString *) input
{
self.enteredCode = [self.enteredCode stringByAppendingString:input];
}
- (void)dealloc {
[enteredCode release];
}
#end
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).