I read several threads about this topic but I can't solve my problem. Please help me. I think I'm too stupid to solve my problem.
My Problem: I have a ViewController and I work with storyboards - I created a NNString property - NSString gets a value - then I wanted to print the NSString with NSLog out but I got always the value null
Thanks for help and sorry for this maybe stupid question. This are little parts of my code, because I think the whole code is to long to post it here.
ViewController.h
#property (nonatomic, retain) NSString *loggedinID;
ViewController.m
#synthesize loggedinID,
...
First method a IBAction
loggedinID = [jsonData objectForKey:#"id"] ;
Now the other method a IBAction, where i want tu use the property
NSLog(#"%#", loggedinID);
Like guys in comment says... First of all get rid of this #synthesize thing. Compiler do this automatically for you when you declare property. From now you should access your property by mutators (setter and getter)
self.loggedinID = [jsonData objectForKey:#"id"]; // Calling setter
[self.loggedinID stringWithString:[jsonData objectForKey:#"id"]]; // Seeter as well
_loggedinID = [jsonData objectForKey:#"id"]; // ivar
[_loggedinID stringWithString:[jsonData objectForKey:#"id"]]; // ivar as well
It's a good way to access your properties via mutators. Only good place, for me, to use ivar are initializers.
Second, check this jsonData... This could be the problem of null in your string property.
Last, at the beginning you've declared #property called loggedinID and later you try to log loggedinFirstName.
At first: you don't need to synthesize anymore.
To answer your question: You are logging a different variable.
loggedinFirstName != loggedinID
Don't use #synthesize in ARC. Try putting value by prefixing self to your string Variable.
Also you can make the string STRONG instead of RETAIN.
Thanks
Related
I have problem assigning a NSString value to a property of my model class. When I NSLog the string out, it is there, but when I try to assign the string to a property and then log out the property, its always null, could you please help me with that?
The property I am trying to assign a value to is defined like so:
#property (nonatomic, retain) NSString * text;
I am assigning the value like so:
NSString *categoryText = [self.pickerCategoryText objectAtIndex:[self.categoryPickerView selectedRowInComponent:0]];
newFilter.category.text = [NSString stringWithFormat:#"%#", categoryText];
I have also tried to alloc and init the property and also assign the value like so:
newFilter.category.text = categoryText;
but none of these solutions worked. I am now totally lost and without any other possible clues, could you please help me with that ?
Thx
At the time when you perform:
newFilter.category.text = [NSString stringWithFormat:#"%#", categoryText];
... either newFilter or category might be nil. If they are nil nothing gets changed.
I would like to verify something that I always use but when I think about it ... I get confused why it worked that way and I sure I read the explanation about it but I cant find it.
As far as I understand apple create their setter as something like this.
-(void)setString:(NSString *)value {
if (_string != value) {
[_string release];
_string = [value retain];
}
}
Now usually I create properties like this.
#property (nonatomic) NSString *string;
#synthesize string = _string;
The question is about next code:
NSString *s = #"Should be deleted";
[self setString:s];
NSLog(#"string check111 =%#",self.string);
s = NULL;
NSLog(#"string check222=%#",self.string);
The same output will be generated. From the setter I can see that my property points on the object that I changed but the property value will be the same.That situation triggers another question (if it works like that why would I need copy attribute).
Can someone provide a short explanation about it? (or concrete link to read).
Tnx A Lot. (I think my question may be already asked in the forum )
This has no effect because you are changing the object to which s points to.
This diagram probably explains it better, originally you have something like this:
Changing the point of s will not affect _string.
The idea of setting the property to copy is in case you set your string property to a mutable string and then change the content of it. See this question.
I guess it would be something like this
NSString *s = #"Should be deleted"; // create autoreleased string
[self setString:s]; // retain string
NSLog(#"string check111 =%#",self.string);
s = NULL; // reset pointer value to null. This operation doesn't affect string object
NSLog(#"string check222=%#",self.string);
// string's retain counter will be decreased by autorelease pool later
In my child view controller, I have a property defined as:
#property (nonatomic, copy) NSString *name;
In view controller A, the Parent, I have the following:
NSString *temp = currency.name; //This is because currency is a Core Data Managed Object.
//I wanted to make sure it wasn't a confounding factor.
childViewController.name = temp;
if(childViewController.name == temp)
NSLog(#"I am surprised");
The problem is that if statement finds equivalency and the "I am surprised" is printed. I thought that == should be checking if they're the same object, and that the use of copy in the property declaration should ensure the setter is making a copy. I checked in the debugger and they are both pointing to the same string. (Which I believe is immutable, which may be why this is happening?)
The same thing happens even if I write childViewController.name = [temp copy];, which I find shocking!
Can anyone explain what is going on here?
Edit: I removed a bit here on worrying about a circular reference which I realized wasn't a concern.
This is an optimization.
For immutable objects, it's superfluous to create an actual copy, so - copy is often implemented as a simple retain, i. e.
- (id)copy
{
[self retain];
return self;
}
Try assigning a mutable object (e. g. NSMutableString) to the property, and you will get the "expected" behavior.
I used to do this till once I found the retain count of one of my retained propery is zero before dealloc function. (This situation is normal or abnormal?)
NOTE: It's a RC condition, not ARC.
For example, I got 4 retained properties below, should they always be released in dealloc function?
If not, how could I know when to release, and when not to release? Manually judge the retainCount?
#property (nonatomic, retain) NSString *fileName;
#property (nonatomic, retain) UIImage *fullSizeImage;
#property (nonatomic, retain) UIImage *thumbnailImage;
#property (nonatomic, retain) UIImageView *checkedImageView;
- (void)dealloc {
[checkedImageView release];
checkedImageView = nil;
[fileName release];
fileName = nil;
[fullSizeImage release];
fullSizeImage = nil;
[thumbnailImage release];
thumbnailImage = nil;
[super dealloc];
}
Well, if the question is "always?", then Wain is almost right...
a SHORT answer is YES...
because in general, when someone set-up a property, it means he's going to use it as a property, that is he uses its setter method to initialize it.
BUT (LONG answer): NO, NOT ALWAYS:
what if you, somewhere in your code, initialize the private var associated to the property without it's setter method? Keep in mind that a property is not a var, but just a useful way to get methods from Xcode to get and set a var associated to it.
in other words, when you write in .h:
#property (nonatomic, retain) NSString *fileName;
and in .m:
#synthesize fileName;
you are declaring a var called fileName and are asking xcode to create 2 (invisible) methods for you:
a setter, used to set a new retained value in fileName:
-(void)setFileName:(NSString *)newString{
if (fileName == newString) {
return;
}
NSString *oldString = fileName;
fileName = [newString retain];
[oldString release];
}
and a getter, used to get the value of fileName:
-(NSString)fileName{
return fileName
}
so, when you somewhere in your code use:
self.fileName = #"ciao";
you are using the property setter method, exactly as if you'd call it directly (and you can do it, the invisible method setFileName: really exist):
[self setFileName:#"ciao"];
doing so, as you can see in the setter method, from now on fileName is retained, and so you should release it in dealloc.
BUT, to answer your question:
if you use the dot rule to set a new string in your var, ok, everything is fine,
but you may decide to set it in the standard way, somewhere, maybe just for mistake:
fileName = #"ciao";
// code
fileName = #"Hallo";
// code
fileName = #"Bye";
this way you are not using the property setter method, but you are using the var directly, and so fileName is not retained, and if you try to release it, well you may get a crash...
PS:
Manually judge the retainCount?
no, never do that
Yes, they should always be released in dealloc. If you get to dealloc and something is already released and not set to nil then you did something wrong with your memory management elsewhere in the app.
Technically in dealloc you don't need to set to nil after releasing but setting to nil after releasing is a generally good idea.
Your dealloc is unnecessarily calling the getter for each property and then immediately releasing it. Just assign nil to release the properties:
- (void)dealloc {
self.checkedImageView = nil;
self.fileName = nil;
self.fullSizeImage = nil;
self.thumbnailImage = nil;
[super dealloc];
}
Although if you are following the current trend of letting clang auto-generate your backing instance variables, then this is better, as it won't cause KVO side-effects:
- (void)dealloc {
[_checkedImageView release];
[_fileName release];
[_fullSizeImage release];
[_thumbnailImage release];
[super dealloc];
}
Yes, they should normally all be released. If you have a retain count of zero, that usually means you've made a mistake somewhere in your memory management code.
You ask: If not, how could I know when to release, and when not to release? Manually judge the retainCount?
Possibly, but you could also let Xcode help you, using static analysis. Go to Product -> Analyze. It will quite often help you find erroneous releases, etc.
When to release? Quite obviously, if your object was holding a reference to another object, and your object goes away, then it should stop holding a reference to the other object. Why would you even look at the retain count? Retain count is about other people holding on the same object, but they are none of your business. They should know what they are doing. So you release the object. You do your job; everyone else has to do theirs. The easiest way, as others said, is to assign
self.someproperty = nil;
If your object was the only one holding a reference, that other object will go away. If others held a reference, it won't go away. Just as everyone would expect. The "release" method should be the only one ever caring about what the retain count of an object is.
I'm trying to switch views in my app using this chunk of code:
self->variable1 = [[NSNumber alloc] initWithInt:0];
self->variable2 = [[NSMutableArray arrayWithCapacity:1];
self->variable3 = [[NSMutableArray arrayWithCapacity:1];
[self presentModalViewController:titleScreen animated:YES];
If I comment out all of the allocated variable lines, the code works fine. If it leave just 1 line in the code crashes with the "EXC_BAD_ACCESS" error. Why is this happening? The variables aren't being used at all, just declared for later use. I'm not getting any compile errors on the lines either. What am I doing wrong?
UPDATE:
Thank you everyone for the help. I change the way I declare my variables to #property/#synth to clean up my code, but it didn't fix the problem. After a long time of fiddling I fixed it. I changed the code from this:
self.variable1 = [[NSNumber alloc] initWithInt:0];
to this:
self.variable1 = [NSNumber alloc];
[self.variable1 initWithInt:0];
and it worked! Can someone explain why this worked and the first line didn't?
Update:
Thank you Peter Hosey for showing me my evil ways. This time I'm pretty sure it's fixed. I was storing my variable Releases in
-(void)release
I didn't realize xCode will release when it needs to. I moved all the variable releases to
-(void)Destroy
so I can release everything on MY command. Now the code works. Thanks again!
I suggest that you declare variable1, variable2, and variable3 as properties, not instance variables. Then, use self.variable1, self.variable2, and self.variable3 to access them.
The dot syntax (self.variable1, etc.) uses the memory management policy you declared on each property; the arrow syntax (self->variable1, etc.) will access the variables directly. The crash is because you created two arrays in away that doesn't leave you owning them, and then did not assign the arrays to a property that would retain them.
You may also want to upgrade your project to use ARC. Then there is no memory-management difference; assigning to the instance variables rather than the properties will not cause the object to be prematurely released, because ARC considers instance variables to be ownerships by default. You may still want to switch to using properties after you switch to ARC, but not to prevent a crash.
In response to your edit:
I change the way I declare my variables to #property/#synth to clean up my code, but it didn't fix the problem.
Then something else was wrong.
You never did say much about the problem itself. You said you got an EXC_BAD_ACCESS, but not what statement triggered the crash or on what grounds you blamed it on the code you showed.
I changed the code from this:
self.variable1 = [[NSNumber alloc] initWithInt:0];
That's the correct code, though. That's what you should be using.
to this:
self.variable1 = [NSNumber alloc];
[self.variable1 initWithInt:0];
Noooo! That code is wrong, wrong, wrong, on multiple levels.
init methods (including initWithWhatever: methods) are not guaranteed to return the same object you sent the message to. NSNumber's initWithInt: very probably doesn't.
That object creates an uninitialized NSNumber object and assigns that to the property. Then it sends initWithInt: to that object, which will return an initialized object, which can be and very probably will be a different object. Now you are holding an uninitialized object (which you will try to use later) and have dropped the initialized object on the floor.
Never, ever, ever send alloc and init(With…) in separate expressions. Always send them in the same expression. No exceptions. Otherwise, you risk holding the uninitialized object rather than the initialized object. In your case (with NSNumbers), that is almost certainly what will happen.
What you should be doing is declaring and synthesizing a strong property that owns the NSNumber object, and creating the NSNumber object in a single statement: either [[NSNumber alloc] initWithInt:] or [NSNumber numberWithInt:]. If you're not using ARC, you'll want the latter, since the property will retain the object. If you are using ARC, they're effectively equivalent.
And if you get a crash with that code, then something else is wrong, so please tell us—either in this question or in a new question—about the crash so we can help you find the true cause of it.
variable2 and variable3 are being autoreleased before you actually access them (presumably) later after presenting the modal view.
At the very least change the lines to:
self->variable2 = [[NSMutableArray arrayWithCapacity:1] retain];
self->variable3 = [[NSMutableArray arrayWithCapacity:1] retain];
or
self->variable2 = [[NSMutableArray alloc] initWithCapacity:1];
self->variable3 = [[NSMutableArray alloc] initWithCapacity:1];
variable1 should be fine.
Best would be to use #property and #synthesize so you can use dot notation:
.h
#interface MyClass : SuperClass
#property (nonatomic,retain) NSMutableArray *variable2;
#property (nonatomic,retain) NSMutableArray *variable3;
#end
.m
#implementation MyClass
#synthesize variable2,varible3;
- (void)foo {
self.variable2 = [NSMutableArray arrayWithCapacity:1];
self.variable3 = [NSMutableArray arrayWithCapacity:1];
}
#end
By default, all instance variables in objective-c have protected scope. So unless you have explicitly declared them public in your interface file as:
#interface MYClass {
#public
NSNumber *variable1;
NSMutableArray *variable2;
NSMutableArray *variable3;
}
//...
#end
then they will not be accessible using the struct dereferencing operator. This is likely the cause of those EXC_BAD_ACCESS errors.