I am working on a subclass of SKNode called UtilityNode
#implementation UtilityNode
- (id)initWithName:(NSString *)rootName {
self = [super init];
if(self) {
[self setName:rootName]; // ?
}
return self;
}
#end
I am setting up a designated initialiser for the new node initWithName: where I am trying to initialise the name of the superclass SKNode when creating the new subclass. I was under the impression that I could just write _name = rootName; but _name was flagged as undeclared. I have got it working (as you can see above) by using [self setName:rootName]; Can anyone shine some light on this, am I doing this correctly?
This is correct. The _name instance variable was probably declared as #private (the default for auto-synthesizing properties) and therefore it is inaccessible by subclasses.
In well-designed class hierarchies and specifically framework classes for which there is no source code available you will find most if not all instance variables inaccessible by subclasses because it hides the implementation detail and makes future changes to the base class possible. Imagine if the base class needed to verify the name property whenever it changes - if subclasses could assign directly to the ivar they would bypass the checks added to the ivar setter method.
PS: I find dot notation friendlier on the eyes:
self.name = rootName;
UPDATE regarding the "don't send messages to self in init/dealloc" rule:
This can easily be avoided by redesigning the class to not take non-essential parameters in its init method. A cleaner version of this subclass would be:
UtilityNode* un = [UtilityNode node];
un.name = #"some name";
If the node absolutely requires the parameter to be set, warn the user via an NSAssert in the method where the name is required to be valid.
Related
What does self mean in Objective-C? When and where should I use it?
Is it similar to this in Java?
self refers to the instance of the current class that you are working in, and yes, it is analagous to this in Java.
You use it if you want to perform an operation on the current instance of that class. For example, if you are writing an instance method on a class, and you want to call a method on that same instance to do something or retrieve some data, you would use self:
int value = [self returnSomeInteger];
This is also often used for accessor methods on an instance (i.e. setters and getters) especially with setter methods, if they implement extra functionality rather than just setting the value of an instance variable, so that you do not have to repeat that code over and over when you want to set the value of that variable, for example:
[self setSomeVariable:newValue];
One of the most common uses of self is during initialization of a class. Sample code might look like:
- (id)init
{
self = [super init];
if(self!=nil) {
//Do stuff, such as initializing instance variables
}
return self;
}
This invokes the superclass's (via super) initializer, which is how chained initialization occurs up the class hierarchy. The returned value is then set to self, however, because the superclass's initializer could return a different object than the superclass.
self is an implied argument to all Obj-C methods that contains a pointer to the current object in instance methods, and a pointer to the current class in class methods.
Another implied argument is _cmd, which is the selector that was sent to the method.
Please be aware that you only get self and _cmd in Obj-C methods. If you declare a C(++) method, for instance as a callback from some C library, you won't get self or cmd.
For more information, see the Using Hidden Arguments section of the Objective-C Runtime Programming guide.
Yes, it's exactly the same as "this" in Java - it points to the "current" object.
Two important notes:
The class itself, e.g. UIView (I'm NOT talking about a UIView object) is itself an object, and there is a self associated with it. So for example, you can reference self in a class method like this:
// This works
+(void) showYourself { [self performSelector: #selector(makeTheMostOfYourself)]; }
// Class method!
+(void) makeTheMostOfYourself { }
Note that the compiler does NOT raise any warnings or errors, even if the self you mean to reference is an object and not a class. It is VERY easy to cause crashes this way, for example:
// This will crash!
+(void) showYourself { [self performSelector: #selector(makeTheMostOfYourself)]; }
// Object method!
-(void) makeTheMostOfYourself { }
// This will crash too!
-(void) showYourself2 { [self performSelector: #selector(makeTheMostOfYourself2)]; }
// Class method!
+(void) makeTheMostOfYourself2 { }
Sadly, this makes class methods a bit harder to use, which is unfortunate because they are a valuable tool for encapsulation through information hiding. Just be careful.
Wow, that many half-correct answers and misleading hints. This let me answer the Q even there is a accepted answer for years:
First of all: It is really hard to compare a concept of messaging/calling in the context of an early binding, static typing language as Java with a late binding, dynamically typing languages as Objective-C. At one point this will break. I would say: No, this is not similiar, since the typing and dispatching concepts of both language are fundamental different so nothing can be similar to the other one. However, …
Then we should differ between the "two sides" of self.
A. Using self
When you use it in a message, it is simply an object reference as any other:
[self doSomething];
[anotherObject doSomething];
Technically both lines works identically (accept of having a different receiver, of course). This especially means, that the first line does not lead to an execution of a method inside the class of self, because self does not necessarily refer to "that class". As every message inside Objective-C (single exception: messages to super)this can lead to the execution of a method in a subclass:
#interface A : NSObject
- (void)doSomething;
- (void)doAnotherThing;
#end
#implementation
- (void)doSomething
{
[self doAntoherThing];
}
- (void)doAnotherThing
{
NSLog( #"A" );
}
#interface B : A
- (void)doSomething; // Not necessary, simply as a marker
#end
#implementation B
- (void)doAnotherThing
{
NSLog( #"B" );
}
In a code like this
B *b = [B new;]
[b doSomething];
The line
[self doAnotherThing];
in class A will lead to the execution of -doAnotherThing (B), because messages to self are late bound as every other message. The result on the console will b "B", not "A". Using self as a receiver you should not think of a single special rule. There is completely none.
(And the above example is a very good example for using self in class methods, because the same situation can occur on class methods. Using the class itself breaks polymorphism, what is one of the worst idea at all in OOP. DO use self in class methods, too.)
B. Getting self
What is self pointing to? It points to the object to whom the message is sent that caused the execution of the current method.
Having …
…[someObject doSomething]… // some object is a reference to an instance object
… as a message, a method is called, in the most simple case …
- (void)doSomething
{ … }
In such a case, self can point to an instance of the class, the method belongs to. And it can point to an instance of a subclass, the method belongs to, too. You don't know. (And this information is preserved using self to send a message as explained above.)
If the message is sent to a class object, self points to the class object, that was the receiver of the message. This is completely analogous. Therefore it is possible that self points to a subclass object:
#interface A : NSObject
+ (void)doSomething;
+ (void)doAnotherThing;
#end
#implementation
+ (void)doSomething
{
[self doAntoherThing];
}
+ (void)doAnotherThing
{
NSLog( #"A" );
}
#interface B : A
- (void)doSomething; // Not necessary, simply as a marker
#end
#implementation B
+ (void)doAnotherThing
{
NSLog( #"B" );
}
Having this classes
…[A doSomething]…
self inside -doSomething (A) points to the class object of B. Therefore [self doAnotherThing] of B(!) is executed. This is clearly different from
+ (void)doSomething
{
[A doAntoherThing];
}
The latter version causes relevant harm to the principles of OOP.
As a side note it is possible that self inside a class method of a root class points to an instance object of the root class or any subclass. You have to keep this in mind, when writing categories on NSObject.
self is an object pointer to the current instances dispatch table. It is an implicit first argument to every member function of an object, and is assigned when that function is called.
In functions like init, you need to be careful that when you call the super class init you reassign self to be the return value as the super class init may redefine what self points to.
super is similar to self except it points to the superclass dispatch table.
Can someone please explain to me (in simple terms) why an instancetype is used in Objective-C?
- (instancetype) init {
self = [super init];
if (self) {
// Custom initialization
}
return self;
}
It's to increase type safety.
Back in the old days, initialisers just returned an object of type id (any object).
With normal initialisers (those that begin with "init", "alloc" or "new"), this wasn't usually a problem. The compiler would automatically infer the type that it returned and therefore restrict any method calls on the object to the instance methods of that class.
However, this was a problem with static convenience initialisers or "factory methods" that didn't necessarily follow the same naming convention - therefore it was unable to apply the same type safety.
This means that with a class like this:
#interface Foo : NSObject
+(id) aConvenienceInit;
#end
The compiler would accept code like this:
NSArray* subviews = [Foo aConvenienceInit].subviews;
Why? Because the returned object could be any object, so if you try and access a UIView property - there's no type safety to stop you.
However, now with instancetype, the result you get back is of type of your given instance. Now with this code:
#interface Foo : NSObject
+(instancetype) aConvenienceInit;
#end
...
NSArray* subviews = [Foo aConvenienceInit].subviews;
You'll get a compiler warning saying that the property subviews is not a member of Foo*:
Although it's worth noting that the compiler will automatically convert the return type from id to instancetype if your method begins with "alloc", "init" or "new" - but nonetheless using instancetype wherever you can is a good habit to get into.
See the Apple docs on instancetype for more info.
Imagine two classes:
#interface A : NSObject
- (instancetype)init;
#end
#interface B : A
#end
The init method from A is inherited to B. However, in both classes the method has a different return type. In A the return type is A and in B the return type is B.
There is no other way to declare the return type for initializers correctly. Note that most programming languages with classes don't even have return types for constructors, therefore they completely avoid the issue.
This is the reason why Obj-C needs instancetype but of course it can be used outside initializers, too.
It is important to use instancetype instead of id in Objective-C if you are also using this code in Swift. Consider the following class declaration:
#interface MyObject : NSObject
+ (id)createMyObject;
- (void)f;
#end
If you want to create a MyObject instance in Swift 5.3 with createMyObject and then call f for this object, you will have to do the following:
let a = MyObject.createMyObject()
(a as? MyObject)?.f()
Now replace id with instancetype in MyObject to have the following Swift code:
let a = MyObject.create()
a?.f()
As you can see now, you can use MyObject.create() instead of MyObject.createMyObject(). And you don't need to use (a as? MyObject) since a is defined as MyObject? and not as Any.
My question is two-part:
First, Say I have a class:
MyClass.h
#interface MyClass: NSObject
-(id)initWithName:(NSString*)name;
#property(nonatomic, strong) NSString *name;
#end
MyClass.m
#implementation MyClass
-(id)initWithName:(NSString*)name
{
if (self = [super init])
{
self.name = name;
}
return self;
}
#end
My question: I know that self will hold the name property strongly. But how will the name property relate to self? What I mean is that I can access name as self.name but while class instantiation, how is the children of self (which in this case is name) related to self? I am imagining the structure of the class as a tree, with the parent holding strong reference to the children and the children holding a weak reference to the parent. I want to know if I am thinking about it correctly or not. My guess is it will be a weak relationship.
Second, if I add a method which has a block that references the name property. So my updated implementation of MyClass.m is:
MyClass.m
#implementation MyClass
-(id)initWithName:(NSString*)name
{
if (self = [super init])
{
self.name = name;
}
return self;
}
-(void)doSomeStuff
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.name = #"Name changed inside block";
}];
}
#end
My second question is: I am not referencing self directly inside my block. So, I guess there is no retain cycle here. But I am referencing name property which is held by self. So does this create a retain cycle?
I know that self will hold the name property strongly. But how
will the name property relate to self?
Each property will have a backing instance variable, conventionally named the same as the property with a leading underscore and a getter and/or setter method. There is no relationship; the property generally makes the class instance larger (due to additional instance variable) and the class larger (due to additional methods).
I am not referencing self directly inside my block. So, I guess there
is no retain cycle here. But I am referencing name property which is
held by self. So does this create a retain cycle?
Yes you are referencing self directly, so a retain cycle is possible. However a retain cycle can only happen under certain circumstances, and it's often just safer to avoid this by creating a weak reference to self and using that within the block.
First: The name property holds no relationship to MyClass, weak or otherwise. (That is, if you pass name to some arbitrary method, it doesn't carry any reference to the MyClass instance where it was a property.)
Second: Since you're simply executing the block rather than storing it, I don't see an opportunity for a retain cycle.
1: The MyClass instance has retained the name property, name property itself has no idea what is MyClass and therefore , there is nothing referring from String-name to the MyClass itself.
2: In the following code
-(void)doSomeStuff
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.name = #"Name changed inside block";
}];
}
self.name = #"Name changed inside block"; is the same as [self setName:#"Name changed inside block"];
So you are actually retaining MyClass instance inside Block and then executing its method to update the name , ( block needs pointer to this Name to change it , right ? block retains class object which contains this property ) , you are not retaining the property name itself.
But how will the name property relate to self? My guess is it will be a weak relationship.
The name property does not have a reference back to self, so the attributes strong and weak don't apply. An object instance is just a collection of instance variables, gathered into a struct. When we talk about object memory management, we are talking about the memory containing that struct. It doesn't make sense to say that a property (really the instance variable backing the property) has a reference to anything. It is simply one part of what self is.
My question: I know that self will hold the name property strongly. But how will the name property relate to self? What I mean is that I can access name as self.name but while class instantiation, how is the children of self (which in this case is name) related to self? I am imagining the structure of the class as a tree, with the parent holding strong reference to the children and the children holding a weak reference to the parent. I want to know if I am thinking about it correctly or not. My guess is it will be a weak relationship.
The children can have a reference to the parent and then it should be weak for the reasons you mentioned. But NSString instances does not have such an up-reference. So there cannot be a retain cycle.
In general it is up to you to manage such inverse relationship. (Core Data does it automatically in its default setters,if you insert a inverse relationship.) Nothing is done automatically, no definition of an up-reference, no setting of a up-reference.
My second question is: I am not referencing self directly inside my block. So, I guess there is no retain cycle here. But I am referencing name property which is held by self. So does this create a retain cycle?
You refer self inside the block, because you use it. Period.
But a retain cycle needs two references. As long as self is used inside the block, but the block is not stored in a property of self (directly or indirectly) no retain cycle can occur.
So in a regular Class, you can override the setter method for a class property:
-(void)setSortBy:(NSString *)sortBy {
// Do other stuff
_sortBy = sortBy;
}
using the _ prevents an infinite loop of the method calling its self.
I am trying to do something similar with a NSManagedObject class, but it does not give the option to use the underscore (_):
-(void)setHasNewData:(NSNumber *)hasNewData {
// update self.modifiyDate
_hasNewData = hasNewData;
}
Gives me an error and suggests I replace _hasNewData to hasNewData.
Is this how it should be done or will it give me an infinite loop?
I want it to update the NSManagedObject's property modifyDate anytime I set hasNewData.
Your first example for a "regular class" works if _sortBy is the instance variable
backing up the sortBy property (e.g. the default synthesized instance variable for
that property).
But Core Data properties are not backed up by instance variables.
When overriding Core Data accessors, you have to use the "primitive accessors",
and also trigger the Key-Value Observing notifications:
-(void)setHasNewData:(NSNumber *)hasNewData {
[self willChangeValueForKey:#"hasNewData"];
[self setPrimitiveValue:hasNewData forKey:#"hasNewData"];
[self didChangeValueForKey:#"hasNewData"];
// do other things, e.g.
self.modifyDate = ...;
}
More examples can be found in the "Core Data Programming Guide".
I've linked a button to the following method:
- (IBAction)searchButton
{
NSString *searchText = _searchField.text;
NSLog(#"lol");
[_search testSearch:searchText];
}
The last line calls the method testSearch within an object named search, defined as follows:
#property (strong, nonatomic) Search *search;
Within Search, testSearch is defined as follows:
-(void)testSearch:(NSString *)testString
{
NSLog(#"HELLO");
}
My final output, when I click search, is only "lol" (each time I click the button). It does NOT print "HELLO", as testSearch should be doing. I have included testSearch in Search.h, so it should be accessible...why isn't this method being called?
You should start by initializing your _search ivar to an instance of Search in your designated initializer (or in viewDidLoad or some other "user gonna use this" method).
- init {
if ((self = [super init])) {
_search = [[Search alloc] init];
}
return self;
}
You should generally avoid lazy initialization in getter methods for a variety of reasons:
It adds unnecessary code; use #property and the default synthesized implementations. Leads to simpler code and less of it.
a getter that does lazy initialization yields a getter that causes mutation. That is inconsistent it is quite odd to see a KVO change notification when calling a getter (unless, of course, you don't fire the KVO notification... at which point, you have non-observeable mutation).
a getter that causes mutation is inherently not thread safe unless you add the code, tricky code, to make it so.
lazy initialization is generally a premature optimization. Unless you have an identifiable memory or CPU performance issue caused by initializing a resource "too soon", then adding the complexity of lazy initialization is wasted effort.
lazy initialization can lead to weird ordering dependencies and other complexities. Far better to have a known entry point for initializing a subsystem than to rely on subsystem X being initialized prior to Y, both by side effect.
The search object you are sending the message to has not been instantiated so you are sending a message to nil. In Obj-C this does not crash the program, instead it does nothing. Its a best practice in Objective-C programming to perform lazy instantiation in the getter method of the iVar. Additionally, you would have to couple this best practice with not accessing your iVars directly and use the setters and getters for whichever iVar you are trying to access. Below is an example of lazy instantiation in the getter method for your search iVar:
-(Search *)search
{
if(!_search){
_search = [[Search alloc]init];
}
return _search;
}
Here is your method call while NOT accessing the iVar directly:
[search testSearch:searchText];