I am trying to get more into detail with Objective-C programming language.
Right now I have a question regarding calling [self] when setting values.
The Apple documentation says "If you do not use self., you access the instance variable directly. (...)"
So assuming I have a dog object that has an instance variable NSString *name.
I create a setter for that instance variable like this without using the [self] keyword:
(void)setName:(NSString *)_name
{
name = _name;
}
When I alternatively create a setter WITH the [self] keyword it looks like this:
(void)setName:(NSString *)_name
{
self->name = _name;
}
In the main-method I create a new dog object and set and return its name value:
Dog *myDog = [[Dog alloc] init];
myDog.name = #"Yoda";
NSLog(#"name of the dog: %#", myDog.name);
In both cases I get a return value of Yoda. But where is the difference between an instance variable call with and without [self] technically? Is it that I call the same variable (memory) just without using the setter method?
self is an implicit reference to the object itself, and generally you only really need to specify it when a parameter and an instance variable have the same name, for example if you had:
(void)setName:(NSString *)name
{
self->name = name; // self used here to differentiate between param and ivar
}
However, you need to be careful with your naming conventions and implementation of methods:
Generally a leading underscore is used as a convention to name the instance variables, not the parameter passed to a method.
In order to set the NSString * object, generally you are going to need to retain it in order to take ownership of the object and to avoid it getting released (which will cause an exception when you access it later).
Therefore your setName method should look more like this:
// _name is the instance variable
- (void)setName:(NSString *)name
{
[name retain];
[_name release];
_name = name;
}
This is only true if you are using MRR, instead of ARC, but you don't specify that so I'll assume you are using MRR.
There is no difference between your 2 examples, in both cases you are modifying the instance variable directly
by self it is meaning self.name which uses the setter method [self setName:someValue];
self->name just means that it is accessing an instance variable so
self->ivar = someVal;
//is the same as
ivar = someVal;
Related
What is the defference if I called
NSString *theNameToDisplay = _name;
or
NSString *theNameToDisplay = self.name;
I know it might be a silly question but I see both versions used a lot and I don't spot a difference in the output?
Thanks!
Assume you have in your .m file this line (and don't have any overriden methods to direct access to _name)
#synthesize name = _name;
It mean that property name (self.name) will use variable _name when you try to access it. In this case self.name is equal to _name
But if you have dynamic property for name, something like this :
-(NSString)name{
return #"1234";
}
then there is a difference. self.name will always return 1234, but _name can be not equal to this value.
Example:
_name = #"555";
NSLog(_name);
NSLog(self.name);
Result:
2012-02-09 14:27:49.931 ExampleApp[803:207] 555
2012-02-09 14:27:49.933 ExampleApp[803:207] 1234
Before asking such question you had better read any objective c properties tutorial...try this http://www.raywenderlich.com/2712/using-properties-in-objective-c-tutorial or any other.
If you created a property you must(ok, should) access an ivar through it so that setter method is called:
- (void)setMyProp:(NSArray *)myProp {
[myProp retain];
[_myProp release];
_myProp = myProp;
}
The first one is to access a variable directly.
The second one is accessing it through the property.
Consider the following code:
NSString *theNameToDisplay = _name;
self.name = #"foo";
NSLog(#"%#", theNameToDisplay);
This may result in a crash because when you set the property, the old value will be released, so theNameToDisplay becomes a dangling pointer. Note that with NSString this does not necessarily happen, especially with literal strings, but it could. It also won't happen when you have ARC enabled.
self.name on the other hand is roughly equivalent to: [[_name retain] autorelease] so theNameToDisplay would still remain valid until the method returns.
See the other answers about the setter part of properties, this is about getters:
Normally, there is no difference in using the getter (self.name) or the ivar directly (_name, name, name_ depending on your taste).
However, there might be cases where something (semi-)intelligent is happening under the hood, and the getter hides some magic. Imagine this custom getter:
-(NSString*)name
{
if ( _name == nil ) return #"No name set";
return _name;
}
Or imagine that you rework your class and the _name ivar gets dropped in favor of a person property encompassing more information, and you want your code to still work without much hassle:
-(NSString*)name
{
return self.person.name;
}
People may or may not like such an approach, but that is outside the scope of this question. The point is, it may happen. So the better choice is to always use the getter.
really no difference, in assigning to other object but it will make great deal of difference if the assignment is done other way around means like self.name = theNameToDisplay; this will be different as the value in theNameToDisplay will get affected by the #property attributes.
I'll provide a simple method and then explain how I see it, if this is incorrect, please let me know and correct me. I feel like I understand 'self' but still doubt my self.
-(NSString *)giveBack {
NSString *string = [NSString stringWithFormat:#"Hi there!"];
return string;
}
-(IBAction)displayIt {
NSString *object = [self giveBack];
[myView setText:object];
}
the "myView" is a UITextView object.
Now as for the 'self'..
I'm basically saying in my -displayIt method that I'm creating a NSString object called 'object' and storing within it a method that returns a string which says "Hi there".
And this method (named 'giveBack') is performed ON the name of my class (whatever I named the project). Is this correct?
No, you are not creating an object called object and then storing a method within it etc. You are creating a variable which can hold a reference to an object and storing within it a reference to an object obtained by calling a method.
[Note: The following assumes you are using automatic memory management (ARC or garbage collection), no mention will be made of reference counts. If you are using manual memoery there is more to consider...]
Adding line numbers to your sample:
1. -(NSString *)giveBack
{
2. NSString *string = [NSString stringWithFormat:#"Hi there!"];
3. return string;
}
4. -(IBAction)displayIt
{
5. NSString *object = [self giveBack];
6. [myView setText:object];
}
Declares giveBack as an instance method of the class, to be invoked it must be called on a particular instance.
The RHS ([NSString stringWithFormat:#"Hi there!"]) calls a class method which creates an object of type NSString and returns a reference, of type NSString *, to that object. The LHS declares a variable (string) which can hold a reference to an NSString object. The assignment (=) stores the reference returned by the RHS into the variable declared by the LHS.
Return the value in string as the result of the method
Declare an instance method called displayIt
RHS: call an instance method (giveBack) on the object instance self - self is a reference to the current object instance when within an instance method (in this case displayIt). LHS: declare a variable, object of type NSString *. Assignment: store the reference to an NSString returned by the method call on the RHS into the variable declared on the LHS.
Call the instance method setText: on the object instance referenced by the variable myView passing it the reference to an NSString found in variable object.
I think, you are generally correct.
But in below mention:
And this method (named 'giveBack') is performed ON the name of my class (whatever I named the project)
I can't understand your meaning.
A class name is just a symbol (that is text for human readers).
Methods of an Objective-C class are indicated by - notation in the beginning of method declaration.
In other words, all method declarations start with - within #implementation CLASS_NAME ... #end block are instance method of CLASS_NAME class.
When we call another instance methods (within a instance method) we use self keyword. Because all Objective C method call must designate target object and, in this case, we are calling ourselves (current CLASS_NAME instance itself). So we use self keyword.
Sorry for my confusing words.. It's harder to explain I thought :-(
you're storing the string returned by 'giveBack', not the method itself. the method is part of the class. 'self' is the instance of the object that you're calling 'giveBack' (and 'displayIt' for that matter) on.
I have an NSManagedObject subclass MyClass with a property myProp, which is defined #dynamic. There are various instances of reading myProp in my code, via [myClass myProp].
Now, I want to define a getter (that returns myProp after appending something to it) for myProp, without changing the various calls to [myClass myProp]. i.e. without creating a getter that is named something other than getMyProp.
My question is, if I create a getter getMyProp, which will override the getter created by NSManagedObject, how do I access the original value that is stored in the database?
To access the underlying values of a managed object you use the following two methods:
- (id)primitiveValueForKey:(NSString *)key
- (void)setPrimitiveValue:(id)value forKey:(NSString *)key
This is often used to convert NSNumber attributes into their 'real' type, for example a bool property:
- (BOOL)isShared
{
[self willAccessValueForKey:#"isShared"];
NSNumber *underlyingValue = [self primitiveValueForKey:#"isShared"];
[self didAccessValueForKey:#"isShared"];
return [underlyingValue boolValue];
}
The willAccessValueForKey: and didAccessValueForKey: are required by the underlying managed object class for handling faults and relationships etc.
And if you do end up writing a setter, you must also wrap the accessor in KVC methods:
- (void)setShared:(BOOL)isShared
{
NSNumber *newUnderlyingValue = [NSNumber numberWithBool:isShared];
[self willChangeValueForKey:#"isShared"];
[self setPrimitiveValue:newUnderlyingValue forKey:#"isShared"];
[self didChangeValueForKey:#"isShared"];
}
Having said this, I would personally not recommend you keep the same method name unless you have a good reason. For 'derived' values you generally want to create a brand new method with a different name. It doesn't take long to do a quick find/replace throughout your code.
EDIT: added willAccessValueForKey:/didAccessValueForKey: (thanks jrturton)
I can't figure out why my app is crashing after a few times I'm doing:
potionsT is nonatomic, retain, readonly.
-(void)First:(NSString*)Potions {
potionsT = [[NSString alloc] initWithString:Potions];
}
-(void)After:(NSString*)Potions {
[potionsT release];
potionsT = [[NSString alloc] initWithString:Potions];
You see, I'm first calling First and after that I'm calling a few times After: and wopes, it crashes. with ECX_BAD_ACCESS.. I'm pretty noob with all that memory manage thing, I know that... Thanks!
The point of retained property is it handles retain and release when you set it.
- (void)first:(NSString*)potions
{
self.potionsT = potions; // will automatically release old value and retain new
}
- (void)after:(NSString*)potions
{
self.potionsT = potions; // same as above
}
Also note how i renamed your Potions to potions, First: to first:, and After: to after:. Objective-C naming convention is to start variables and methods with lowercase letter, and class names with capital.
Did you #synthesize the property in the #implementation for the class? If so, then you should use:
self.potionsT = Potions;
if you use
potionsT = ...
then you are accessing the ivar, not the property. To access the property and let it do the memory management for you, you must precede it with an instance reference, and that can also be self.
If you use the property, you should not release potionsT manually, since the property already does that for you.
If you've set up potionsT as a property, you should access it that way:
-(void)first:(NSString*)potions {
self.potionsT = potions;
}
-(void)after:(NSString*)potions {
self.potionsT = potions;
}
In both cases, I changed your code to use the accessor for potionsT (that's what the self.potionsT means). I'm also not creating a new string, but just retaining the provided one. Since NSStrings are immutable, the result is the same. For best results, though, change the potionT property from retain to copy. That way, if a mutable string gets passed in, it'll be copied instead of retained (and immutable strings will still just be retained).
I'm declaring an NSString property in a class and objective-c is complaining that:
NSString no 'assign', 'retain', or 'copy' attribute is specified
It then casually lets me know that "assign is used instead".
Can someone explain to me the difference between assign, retain and copy in terms of normal C memory management functions?
I think it is drawing your attention to the fact that a assign is being used, as opposed to retain or copy. Since an NSString is an object, in a reference-counted environment (ie without Garbage Collection) this can be potentially "dangerous" (unless it is intentional by design).
However, the difference between assign, retain and copy are as follows:
assign: In your setter method for the property, there is a simple assignment of your instance variable to the new value, eg:
- (void)setString:(NSString*)newString
{
string = newString;
}
This can cause problems since Objective-C objects use reference counting, and therefore by not retaining the object, there is a chance that the string could be deallocated whilst you are still using it.
retain: this retains the new value in your setter method. For example:
- (void)setString:(NSString*)newString
{
[newString retain];
[string release];
string = newString;
}
This is safer, since you explicitly state that you want to maintain a reference of the object, and you must release it before it will be deallocated.
copy: this makes a copy of the string in your setter method:
- (void)setString:(NSString*)newString
{
if(string!=newString)
{
[string release];
string = [newString copy];
}
}
This is often used with strings, since making a copy of the original object ensures that it is not changed whilst you are using it.
Cocoa uses reference counting to manage memory. Objects with a reference count of 0 are deleted.
assign - does nothing to reference count simply points your variable to the data
retain - points your variable to data and adds 1 to reference count, data is guaranteed to be there while your variable is still alive
copy - makes a copy of data, points your variable at it and makes the retain count 1
More detail here, at Apple's own documentation.
assign - the ivar is set by doing a simple assignment. Implementation:
- (void) setFoo:(NSString *)newFoo {
foo = newFoo;
}
retain - the ivar is sent the retain message before doing the assignment. Implementation:
- (void) setFoo:(NSString *)newFoo {
if (foo != newFoo) {
[foo release];
foo = [newFoo retain];
}
}
copy - the ivar is sent the copy message before doing the assignment. Implementation:
- (void) setFoo:(NSString *)newFoo {
if (foo != newFoo) {
[foo release];
foo = [newFoo copy];
}
}