I have 2 classes A and B,B is inherited from A,A is inherited from NSObject.Class A has a function -(void)init:
- (void)init {
if (self = [super init]) {
NSLog(#"A");
}
return self;
}
B has:
- (id)init {
if (self = [super init]) {
NSLog(#"B");
}
return self;
}
After compilation I have "A" and "B" in my console,despite of condition in B "if (self = [super init])" can't be true,cause its superclass init method returns void.Any ideas?
P.S. I know that init method must return id,I'm interested why this works while it shouldn't.
Listen to Chuck. He's smart :)
I'll try to add a bit more detail.
One way to think about this is "If both were declared -(id)init how would A return its value to B"?
It goes something like this. The return self statement would take the pointer to A and put it in an agreed upon location. This location would be defined in the ABI. On a OSX/x86-64 machine, it's the RAX register (IIRC). So return self really says "write the pointer to self into RAX".
Then when B regains control it knows the return value is in RAX and can use it however it likes. Note you didn't remove the return self statement from A's implementation, so self was probably still written to RAX where B found it and used it. Or maybe RAX still had a pointer from the NSObject init implementation. You'd have to disassemble it to know for sure.
Now let's say you didn't keep the return self in A's implementation. Now there's some random junk in RAX which B is going to try to use like it's a pointer to an A. This is where the undefined behavior Chuck mentions comes in. If you're lucky it will just crash.
I'm guessing your code above gave some compiler error/warning that you had to suppress?
You're invoking undefined behavior by assigning the result of a void function call. Undefined behavior means pretty much anything can happen. This falls under the header of "anything," so it can happen.
As for why the compiler isn't noticing your mistake: You probably neglected to declare the override in your header, so it's assuming that your method has the same signature as the nearest declaration it can find, NSObject's.
Related
I just learned how to use the Result type recently from Sean Allen's video, and I get the idea of using it. However, while I was writing a code, there is a line I don't understand.
The line is 87 in the picture (or this -> guard let self = self else { return } )
At first, I was just doing the same stuff as he did, but I wonder why he add the line in the code. I think he wrote it because the self can be nil and wanted to make sure if the self is not nil and return from the function if it gets nil.
And my question is
when or in which situation the self can be nil?
and
if self gets nil, I think it won't trigger the following line (the one for checking the result), so both of the updateUI function and presentGFAlert... function won't be triggered and nothing shows up on the screen, right?
Its because the closure defines its reference to self as being weak, this means if self is released, the block closure will not prevent self from being destructed, getting a reference count of 0. You can deal with this in the code in the closure, by using all references to self as self?, but this mean self could became nil mid way being executed, by using guard let self = self else { return }, you are saying if execution gets here, I want a strong reference to it, so the object will continue being available until the execution of the of the closure complete, basically all or nothing. This in the past could only happen with multi threaded apps, but with apples new async thread model making cooperative threads more common this is potential more possible.
Your concern is correct. Because getFollowers is an async task, user could go back to previous screen while the task is running. In that case, self could be nil and the return is okay.
On the other hand, to make sure there's no problem with completion block of getFollowers task, self will be captured as strong reference, that could cause memory leak even if user already leave that screen.
He uses weak self to prevent that happens.
I'm getting use of undeclared identifier self error when I'm calling any method from AudioPlaybackComplete. Any of you know why or how can I fixed?
static void AudioPlaybackComplete(SystemSoundID ssID, void *data)
{
[self doSomething]; /// error use of undeclared identifier self
}
You will need to pass the object (the one you want refered to by self) by using the data pointer *data . Either point at the object directly (then cast it back to an object of the proper class/type for use), or pass in the object as an element of a C struct pointed to by *data.
Objective C method calls do this as well, but pass and set self automatically and hidden from view by the compiler, instead of explicitly by having to code it. Since you are using a C function, you will have to code this yourself.
You're calling self from within a static function - self refers to a specific instance of the class.
What is the difference beetween :
// 1
-(id) init {
self = [super init];
if (self) {
... do init ....
}
return self;
}
// 2 - I guess it's exactly the same as previous
-(id) init {
if (self = [super init]) {
... do init ....
}
return self;
}
// 3 - is this one a really bad idea and if yes, Why ?
-(id) init {
self = [super init];
if (!self) return nil;
... do init ....
return self;
}
// 4 - I think this one sounds OK, no ? But what is returned... nil ?
-(id) init {
self = [super init];
if (!self) return self;
... do init ....
return self;
}
EDIT : Added thanks to Peter M.
// 5 - I really like the readability of this one
-(id) init {
if(!(self = [super init])) return self; // or nil
... do init ....
return self;
}
they all do the same thing but first one are commonly used because apple suggested
the second one was commonly used but it will introduce compiler warning on new version of Xcode so apple decided to change it to first one
The common one used by Apple
Does the same but the compiler does not know if you didn't mean == instead of =. You can block the warning by using another (...) around the expression, but it's not easy to read.
This one would be preferred by any good coding standards (usually not as a one-liner but with bracers). When your initialization code is long, this one significantly increase readibility.
The same as 3 but you lose some readibility. Returning nil makes the code easier to understand (maybe this is only my opinion, someone else can say 4 is better than 3).
In summary: use 1 or 3. When initialization code is long, you should use 3 to avoid having most of method code in one if block. Apple uses only 1 but don't follow it blindly. Apple has no documented coding standards and sometimes what they recommend is very questionable.
You can use 4 instead of 3 but don't mix 3 & 4 in your code.
1 is suggested simply because it's clear.
2 works, but is just bad practice. Don't embed logic in your conditionals if you don't have to.
3 makes my head hurt. Typically, you want to avoid negative checks if you can.
4 same as 3.
Both 1 and 2 are easier to read than 3 and 4, also because they are the one's used in Apple's code; many developers are used to 1 and 2.
Number 4 and 3 are the same, as if !self evaluates as true, then it means self is nil, so the statement return self is equivelant to return nil. Some people will say you shouldn't have multiple exit points (returns) in a method, but in reality having multiple return statements can cut down the number of if statements (which reduce the readability)
Number 2 has been common, however in the latest versions of xcode you will get a compiler warning if and if statement contains a single = (as many times it is a typo, when you intended to use == to compare BOOL values). To silence this warning you have to surround the statement with brackets, so instead of if (foo = bar) you would have if ((foo = bar))
But Apple must have realised that Number 2 is used a lot, and they added an exception to the rule, so you using it will now not cause a compiler warning.
As Number 2 is an exception to the rule, you shouldn't really use it. So that makes Number 1 the preferred method.
To add to the fray .. I prefer:
if(!(self = [super init]) ) return self;
Keeping it all on the one line, and no warnings in XCode 4.2 :D
Are there any difference between following ways to init self?
First:
- (id)init {
self = [super init];
if (self) {
}
return self;
}
Second:
- (id)init {
if (self = [super init]) {
}
return self;
}
I like to use second way to init self. But I often see the first way when I create a new class by Xcode, it will generate those codes automatically. I am afraid the second way will make some errors in some condition which I don't know.
Nope, they are the same.
The second method is just missing out the first assignment of self
Another way you might come across is this:
- (id)init {
if (!(self = [super init])) {
return nil; // Bail!
}
// Further initialisation
return self;
}
This puts the exceptional condition in the if statement, and keeps the code that you expect to run normally (the Happy Path) closer to the left margin.
In C and most(if not all) languages these two are same.
First
a = b;
if (a) {}
Second
if (a = b) {}
First one is just using one more line.
However, they are not same as
if (a == b) {}
They’re equivalent and you can safely use either of them. Some people prefer not to use
if (self = [super init])
because it is a tad overloaded: it means ‘assign the return value of [super init] to self, and then evaluate self as a (boolean) condition’.
At first glance, one could misread that code, interpreting the assignment operator = as being the equality relational operator ==, i.e., ‘compare self to the value returned by [super init]’, which is not the case.
This can be particularly confusing for programmers that are new to C. Not every programming language allows assignments in expressions, that is, assignments must be in a separate instruction.
Both are functionally equivalent but using assignments where conditional expressions are expected is discouraged as bad programming practice because it's usually accidental, e.g:
if (myVar = 5) {
printf("The variable was 5\n");
}
When you actually meant to write:
if (myVar == 5) {
...
However the Objective-C init code is usually an exception to this because it's a well known sequence and repeated a lot, so for convenience some people may choose to write the assignment within the conditional expression.
Ok I think my understanding of properties in objective c may not be what I thought it was.
In my program I have a singleton that contains my class.
In my class during the init I assign a value from the singleton to my property.
I then assign a value to a property of that property.
However it does not keep the value and when I do a compare of the value in the singleton nothing has changed. What is going on here? Any ideas?
#interface MainGameLoop : NSObject {
MapData *mapData;
}
#property (retain) MapData *mapData;
-(id) init
{
self = [super init];
GlobalVariables *sharedManager = [GlobalVariables sharedManager];
self.mapData = sharedManager.mapData;
return self;
}
In a function of my class:
works:
sharedManager.mapData.currentPlayer = newCurrentPlayer;
does nothing:
self.mapData.currentPlayer == newCurrentPlayer;
self.mapData.currentPlayer == newCurrentPlayer;
Are you sure that you want two equal signs there? That statement is syntactically correct and will evaluate to either true or false.
== is a Boolean operator, while = is an assignment operator. Like what Dave said, if you are using an if statement such as if (self.mapData.currentPlayer == newCurrentPlayer) {…}, you would want to use == because it would evaluate to true or false, while = would be used to set the value of a variable, which is what I think you are trying to do.
If it's any consolation, I've made that mistake too many times to count…
Something that I do is to use NSLog() or printf() to make sure that each step is working correctly.