Is my understanding of 'self' correct? - objective-c

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.

Related

Keeping objectiveC object valid outside the scope of a function

I'm a bit confused about ARC behaviour when setting variable that is an input pointer, and is expected to remain valid outside function scope.
considering the following example that uses openDirectory framework.
#interface bbb
-(bool)doSomethingWithADRecord:
-(void)obtainADRecord(NSString*)user
-(NSString*)getADrecord:(ODAttributeType)attr fromRecord:(ODRecord*)record;
#end
#interface bbb {
ODRecord *_myRecord;
}
#end
#implementation bbb
-(void)doSomethingWithADRecord:
{
// here we access _myRecord and expect it to be valid.
}
-(bool)obtainADRecord:(NSString*)user
{
...
// here I call the method that will set the member _myRecord from type ODRecord*
// whose scope related to the lifespan of the containing class (bbb)
[self getADrecord:attr toRecord:_myRecord];
}
// the following function should set the variable record to be used by the caller.
-(NSString*)getADrecord:(ODAttributeType)attr fromRecord:(ODRecord*)record {
...
// here a set an ODQuery object.
ODQuery *query = [[ODQuery alloc] initWithNode ...
// queryResults is an array of items from type ODQuery*
NSArray* queryResults = [query resultsAllowingPartial:NO error:&err];
for(ODRecord *item in queryResults) {
if (/*some logic*/)
{
//option 1: just regular set operator, expecting the ARC will do the retain itself
record = item;
//option 2: explicits take a reference on that item.
record = [[item retain] autorelease];
return #"found item";
}
}
}
#end
To Clarify my question, I seek to know which one of the 2 options I stated above is the correct one , in terms of passing the reference to record and eventually to _myRecord, so it will store the correct value even after the temporal list of queryResults will be cleaned.
Notice that in both options I simply setting the pointer value without initiate new object from type ODquery and copying the data to this new object.
thanks !
I'd like to know whether simply doing record = item will be enough for the data pointed by this object to last beyond the scope of the function getADrecord
You are misunderstanding how parameters work; a parameter, such as record, is essentially a local variable which is initialised to the value passed in the call.
Therefore any assignment of an object reference to record will have zero effect on the lifetime of the referenced object outside of the scope of getADrecord as record is local to the function.
To return a value of type T via a parameter the type of the parameter must be of type "pointer to a variable of type T". An example with a simple value type:
- (void) add:(int)value // an int value
to:(int *)ptrToVariable // a pointer to an int variable
{
// note the need to indirect (`*`) through pointer stored in
// `ptrToVariable` to access the pointed at variable
*ptrToVariable = *ptrToVariable + value;
}
int x = 31;
[self add:11 to:&x]; // &x creates a pointer to the variable x
// x = 42 after call
Now you don't want to return a simple value type but a value which is a reference to an object and you wish ARC to manage the lifetime correctly. This is a little more complicated.
Under ARC a variable which holds a reference to an object has both a type and an ownership attribute; this attribute informs ARC how to handle storing references in the variable. The common ownership attributes are __strong and __weak, without an explicit attribute __strong is assumed. So your instance variable declaration is shorthand for:
ODRecord __strong *_myRecord;
This declaration means that for any reference to an ODRecord stored into _myRecord ARC will keep the referenced ODRecord alive at least as long as _myRecord exists and the reference is not overwritten by a different reference or nil. It is "at least as long" as the same reference could be stored elsewhere and these will also effect the lifetime.
Almost there! To return a reference to an ODRecord via a parameter the type of the parameter must be "pointer to a variable of type strong reference to ODRecord, i.e.:
- (NSString *)getADrecord:(ODAttributeType)attr
fromRecord:(ODRecord * __strong *)record
now an assignment such as:
*record = item;
will result in an assignment to the pointed-at variable and as that variable is of type ODRecord __strong * ARC will ensure the referenced ODRecord will live at least as long as a reference to it is stored in the pointed-at variable.
Your call to this method must pass a pointer to your variable:
[self getADrecord:attr toRecord:&_myRecord];
Notes:
"out" parameters are not often used in Objective-C with the notable exception of error returns – these are of type NSError * _autoreleasing * and Apple names this usage as "call-by-writeback".
For a deeper explanation of ARC and returning values via parameters see Handling Pointer-to-Pointer Ownership issues in ARC and NSError and __autoreleasing
Important:
As pointed out by #matt in the comments your code contains retain and autorelease calls which are forbidden in ARC and therefore if your code is compiling you DO NOT have ARC enabled. For new projects ARC will be enabled, for existing projects you may need to enable it your project's Build Settings, the setting is called "Objective-C Automatic Reference Counting".
A call to "autorelease" means the object has an additional retain count that will go away when you leave the current autorelease scope, which is typically when the current event is finished.
record = item is obviously not enough, because record's retain count goes away when records leaves scope, that is when the function returns.
But what you do - calling autorelease for each item makes sure that all the items remain allocated for a while, not just "record".

Why a pointer to no object can be asked to execute a setter?

I creating a pointer does not create a Class object.
But it can be send method to execute in another instance method.
I think just a pointer to the object can be asked to execute a method.
Why the "t" can use setter in the method like this image?
This happens because Xcode only checks if declared type of t variable has visible readwrite property named a. It doesn't care if t is actually object or something else at this point. For example, it cannot know if t is object or nil, or anything else in such situation
- (void) method:(One*) t{
t.a = #"Some string";
}
You can call it like this
[two method:nil];
Xcode won't complain. You can even do this
One *t = (One *)[[NSObject alloc] init]; //warning here
t.a = #"Some t"; //Xcode doesn't care, that t is actually NSObject and doesn't respond to setA:; But you get a runtime error
nil in ObjC responds to all selectors - you can call any visible method on nil object and you won't get a warning nor error. Just silently passes by

Are Objective-C Objects Pass By Value or Pass By Reference?

So I have something like :
- (void) printString:(NSString *)string
{
NSLog(#"%#", string);
}
NSString *string = #"Blach";
[self printString:string];
Would string be passed in by value or reference? What about something like NSError?
NSError *error = [NSError errorWithDomain:someDomain
code:-101
userInfo:someInfo];
-(NSString *) doSomething:(BOOL) val withError:(NSError **)error {
if(!val)
{
*errorPtr = [NSError errorWithDomain:something
code:-101
userInfo:someInfo];
}
}
You can never refer to an Objective-C object by anything other than a pointer, so for all intents and purposes, everything is pass-by-reference. That said, the actual pointer values are passed by value, just like in C.
Everything of every type in Objective-C is pass-by-value only.
The question is invalid because "objects" are not values in Objective-C and therefore cannot be "passed" -- you cannot have a variable or expression whose value "is an object" (a bare object type is not allowed in the language) -- instead, "objects" must always be manipulated behind pointers to objects. Since "objects" are not values and you cannot "pass" them, it is meaningless to ask about whether they are "pass-by-value" or "pass-by-reference".
Objects are passed by reference. The important distinction, to my mind, is whether the called method has a reference to the same object as the caller or if it has a copy. It has a reference to the same object.
If the object is mutable and the called method mutates it, it affects the object that the caller has, too (because it's the same object).
In the case of an NSError** parameter, it is actually the pointer (not an object) which is being passed by reference. A method with such a parameter can actually modify the caller's pointer, making it point to a different object.

Objective-C instance variables accessor methods

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;

Objective-c symbols ** & +-

Just when I think I'm getting comfortable with Objective-c the mentioned symbols totally throw me down a rabbit hole...
** a double pointer??
& what sort of things can I do with &reference, is a #property? a full on object? weird pointer razzledazzle?
± I see both a + or a - before method declarations; I've seen Java annotate some datatype declarations by manually typing the + and the magic of compiling in Eclipse would change them to a -
I'm likely asking repetitious questions and/or way outta the ballpark on my guesses; thanks for answers/edits.
You're getting into the C portion that objective-c is built on top of.
** is a pointer to a pointer. Since functions in C take arguments by value, it means you can't change the value of the argument in that function. But, by providing a level of indirection and passing a pointer to the pointer, you can change the value.
& means it's a reference. If an argument takes a ** and you have a * variable, pass a reference to it.
Foo *foo;
[self changeFoo: &foo];
- (BOOL)changeFoo: (Foo **)foo
{
// dereference the double pointer and assign a val = alloc init returns a *
*foo = [[Foo alloc] init];
return YES;
}
A common usage in objective-c / cocoa is NSError. It's essentially an out argument.
NSError *err;
BOOL success = [self doSomething:#"Foo" error:&err];
- (BOOL)doSomething:(NSString*)withData error:(NSError**)error
{
}
As you might know, a pointer points to the address of an object and is the way you reference an object. A double pointer is sometimes used in Objective-C, mainly for returning NSErrors, where you want to get back the address, i.e. a pointer, to an error object (NSError) if an error occurred, thus you pass in a pointer assigned to null and the caller can change that pointer so that it points to the address of another pointer which in turn points to an NSError object.
The ampersand (&) is mostly used by the lower level C APIs, e.g. Core Graphics. They are used to reference things, like the current context. As long as most of your code uses square brackets around its method calls you won't see these very often.
Using a + or a - before a method declarations is used to differentiate between class (+) and instance (-) methods. A class methods is called on the class itself (such as alloc), while a instance method is called on an instance of that object (such as init).
- and + before a method declaration designate an instance method and a static class method. To use an instance method you have to create an object of your class before you can call its method, a static method can be called directly from a class type