Need an iPhone Programmer judge every step and every pointer == nil? - iphone

for example:
NSString *myString = [[NSString alloc] init];
if (nil == myString) {
return;
}
Need I do this??Thank you!

No, you don't need to do that, and I can't say I've ever seen code that made pervasive use of that pattern.
Also, the if statement can be shortened to:
if (! myString) {
return;
}
...which is equivalent though no less superfluous. Checking for nil can be useful, but is typically not done immediately after object instantiation. Instead the typical case is to do it to ensure that an object is not over-released, for instance using a pattern like:
if (myObj) {
[myObj release];
myObj = nil;
}
Note that calling any method on nil is allowed in Objective-C, so less harm is caused by an unexpected nil value floating around than in languages like Java where attempting to do anything with a null reference throws an exception.

Objective-C allows to call on nil pointers, that differs the language from many others and allows to skip some checks. Of course, it's still wise to check for == nil in some particular cases, however, you don't have to check every step in the code. Take a look at Apple's documentation and samples and try to follow their style.

Frankly, most iPhone app code produced these days assumes that an out-of-heap condition (the only logical reason for such a simple instantiation operation to fail) never occurs in normal operation. Only when creating large (eg, image) objects might one check for allocation failure.
Of course, init routines can fail for a host of reasons, so checking for nil following a complex instantiation operation may be warranted (depending on the object type). (And remember that many other methods of some objects can return nil under some circumstances as well, so you need to read the specs and code accordingly.)

Related

Should all object variables be optional in Swift?

Swift Programming Language book doesn't discuss this but should all object variables be optional in Swift? Because technically speaking, an object creation can fail and return nil (as in the case of Objective-C). So should all object variables in Swift for Swift classes (or at least for all Foundation classes) be declared as optional?
let obj:NSData? = NSData()
This might be opinion based but I think that usually you want variables to be non-optional.
There are not many objects initializers that can actually return a nil.
In Obj-C you don't check whether all initialisers return nil.
NSArray *array = [[NSArray alloc] init];
if (array != nil) { //would you test this?
}
In the same way, don't let all object variables be optional in Swift. Only the ones when you actually want to check for nil values.
By the way, in pure Swift the Object initializers can't return a nil because they don't actually have a return value. In Swift, the object initialization can't fail, so we are speaking only about Obj-C interoperability here.
One example to answer the comments:
NSData *data = [[NSData alloc] initWithContentsOfFile:#"some_file"];
in Swift:
var data = NSData(contentsOfFile: "some_file")
If the file doesn't exist, in both languages we get a nil. In Swift, we have an implicitly unwrapped optional, so the assignment itself won't fail and we can still test for nil if we want to.
If we expected data could be nil, the behavior would be the same in both languages, we would solve the problem somehow. If we haven't expected it, it's a bug because everything else is undefined behavior.
In Swift, the application will crash early - the first time you try to use data.
In Obj-C, the result will be absolutely random - note that we never expected data to be nil, so our next statement could be:
[array addObject:data];
crashing the application.
However, because of the nature of Obj-C, thousands of statements could happen before the bug actually reveals itself and it can reveal itself very strangely - for example: data parsing could fail, UI layout will fail because items will be missing when we expected them and so on. We could also get a late crash. Nevertheless, the application behavior will be undefined since the nil return because we didn't account for that possibility:
...things may not be executed, but it certainly won't crash the program or leave things in an unstable state...
Both statements from the comment are false.
The late manifestation of errors is one of the biggest problems when debugging Obj-C applications, making them unsafe. Sometimes they don't crash but that doesn't mean they are working correctly. Swift considers and early crash a much better alternative than a hidden nil object propagating itself through the application and crashing the app hours later.

Can we check if the object is nil or not, before going to release in dealloc method of a class

Can we check the object is nil or not before going to release in dealloc method. I am new to objective C. Is this right way to avoid segmentation issues?.
-(void)dealloc{
if(stringObject!=nil){
[stringObject release];
}
}
Testing for nil before release is fully redundant in Objective C and will not add any resiliency to your code.
Indeed, the whole point of segmentation faults (EXC_BAD_ACCESS) is having a pointer which is not nil, thus points to some memory, and accessing that piece of memory after it has been freed.
If the pointer is nil in the first place you will not be possibly able to access any memory with it and you will not have a segmentation fault in Objective C (unlike C or C++).
The real solution to segmentation faults is correct memory management. If retain/release management seems too complex, you can have a look at ARC, which has its own intricacies, though (although much less than manual retain/release management).
A simple
if(stringObject)
will do, if you just want to check if the variable points to an object.
But with Objective C it is not necessary to test for nil because an message to a null object will simply do nothing. So it is enough to say:
-(void)dealloc
{
[stringObject release];
stringObject = nil;
[super dealloc]; //added because of the comments
}
Under ARC, you can leave out the whole dealloc in most situations, because 1) the release is managed automatically, and 2) the call to dealloc is the made just before the object ends it's life, so the nil is not necessary. However, if you use custom c-style allocation you may still need an alloc method. But this belongs to an advanced topic.
Here's a link to the dev guide on working with objects in general:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html#//apple_ref/doc/uid/TP40011210-CH4-SW1
This suffices as a nil test (your way is also correct, just slightly longer):
if (stringObject)
{
//do something
}
But in a simple case like yours, you don't even have to do that, because in Objective-C, sending messages to nil objects just means nothing happens:
[aNilObject doSomething]; //nothing happens, this is perfectly valid and won't throw an exception; it won't even log anything. Once you're used to it, it's great and avoids lots of boilerplate nil checks.
Going further, in your case, you should switch to ARC (after you're done learning manual retain and release, which is a good exercise).
Your code would then look like this:
//you don't need to call dealloc at all in ARC :)
Yes you can. Before ARC there was a very common macro defined
#define SAFE_RELEASE(object) if (object != nil) { [object release]; object = nil; }
NOTE: However, sending a message to nil will return nil.

What happens if you pass nil at runtime to a parameter that shouldn't accept that?

Say I have a method that takes a CLLocationCoordinate2D. I can't pass nil directly to that in code; the compiler complains. However, the following compiles. So what happens at runtime?
CLLocation* loc = nil;
[self passMeCoordinates:loc.coordinate];
This is an interesting question. I assume your earlier code was:
[self passMeCoordinates:nil];
The compiler complains about this because CLLocationCoordinate2D is not an object. It's a C-style struct. So, you can't pass an object/pointer (nil) where a struct is expected. (They're not the same size, etc.)
If I slightly paraphrase your code to:
CLLocation* loc = nil;
CLLocationCoordinate2D coord = loc.coordinate;
[self passMeCoordinates:coord];
The question comes down to "what value does coord have". As you may know, the rule in Objective-C is that if you send a message to nil (as we do here -- loc.coordinate is equivalent to [loc coordinate]), then you get back 0. But what if we're expecting a struct? As I just mentioned, it's not the same size as an integer. Well, it turns out that the result depends on what compiler you're using:
LLVM 3.0+ (Xcode 4.2+): returns all zeros, so it's equivalent to a coordinate of (0,0): Can I rely on nil UIView returning CGRectZero for its frame?
LLVM Earlier/GCC: a struct can be filled with garbage/undefined contents, so it could be anything.
Loc.coordinate is a structure so you cannot pass nil for that.
And method that return C structure are not safe to be call on nil.
So your warning is not about passing nil as argument.
As of your question about nil as argument. Well it depends on the method, some handle nil gracefully others don't. Refer to the documentation of those method it's usually said if you can or cannot pass nil as argument.
As others have pointed out, you're dealing with a struct property of your location object, and therefore nil will be problematic. You should only be using nil with objects.
But more generally, you should never assume that any method will accept nil as a parameter. It all varies from method to method. For the built-in classes, it will generally specify in the documentation when a nil parameter is acceptable. If it doesn't say that nil is permissible, it's wise to assume that it's not.
Whether your own code accepts a nil parameter is entirely dependent upon what you do with that parameter and if you're doing anything that requires it to not be nil, whether your code is checking for non-nil values and handling appropriately, etc.
As a completely random example, if you have a method that does:
NSMutableArray *array = [NSMutableArray array];
[array addObject:text];
This will generate a NSInvalidArgumentException exception if text is nil.
Bottom line, it all varies, method to method. Refer to the documentation for the methods in question to see if nil is permissible or not.
The one general exception to the "don't use nil unless the documentation says you can" rule is that when sending messages to a nil object (i.e. invoking a method on an object that is nil). That is permissible (but obviously does nothing). As the documentation says:
In Objective-C, you can often send a message to nil with no ill effects. Return values from messages sent to nil are guaranteed to work as long as what is returned is typed as an object.
At runtime nil will get passed to your method. The compiler does not do runtime checking , it only does compile time type checking.

objective-c: initialize variable to nil

Does anyone know if the following code could be problematic:
NSString *addchar = nil;
if (case1)
addChar = [[firstname substringToIndex:1] capitalizedString];
else
addChar = [[fullname substringToIndex:1] capitalizedString];
Assume that firstname and fullname aren't null or empty. Does initializing the NSString object and setting it to 'nil' cause some possible problem? It seems to cause my app to freeze, but only for a very few users, and only those users, but it doesn't have anything to do with different input strings or empty strings. So I'm trying to isolate the problem, but I don't know the difference between
NSString *addChar;
and
NSString *addChar = nil;
Thanks.
Either form is perfectly acceptable. The problem you're having is elsewhere. I recommend doing some code profiling with Instruments to figure out where this issue is occurring.
Without the nil initializer, in some cases your variable may be initialized with garbage (whatever was in the memory space previously). There are specific rules regarding which types of variables (scope-based, static storage, etc.) are nil-initialized automatically for you, but I've always found that it's easier to explicitly initialize all variables instead of memorizing those rules.
That said, because both branches of your if statement clobber any previous value of addChar, there should not be any case in which you can see an invalid value. But it's certainly not hurting anything to explicitly initialize to nil, and if a future maintainer comes along and changes the code paths you might find that the initializer saves you!
You should always initialize to nil if variable is not initialized otherwise.
You can send messages to nil they will be ignored.
NSString * str = nil;
NSLog(#"%#", [str description]);
Outputs:
2009-12-15 08:59:03.352 x[11775] (nil)
Of course I don't need to call description explicitly, I'm just demonstrating call to nil.
There is no difference here since you don't read addChar in your code. Moreover, the compiler may sometimes initialize addChar to nil for you if you don't do it explicitly (depending on the scope of addChar's declaration).
See related question at this place.
From now on, when you use ARC, the strong, weak, and autoreleasing stack variables are initialized to nil:
https://developer.apple.com/library/ios/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226-CH1-SW5
Additionally, since dawn of times, in ObjC the instance variables are initialized to zero:
Are instance variables set to nil by default in Objective-C?

EXC_BAD_ACCESS on iPhone when using "obj != nil

I've got a very simple line of code in Objective-C:
if ((selectedEntity != nil) && [selectedEntity isKindOfClass:[MobileEntity class]])
Occasionally and for no reason I can tell, the game crashes on this line of code with an EXC-BAD-ACCESS. It usually seems to be about the time when something gets removed from the playing field, so I'm guessing that what was the selectedEntity gets dealloc'd, then this results. Aside from being impossible to select exiting Entities (but who knows, maybe this isn't actually true in my code...), the fact that I am specifically checking to see if there is a selectedEntity before I access it means that I shouldn't be having any problems here. Objective-C is supposed to support Boolean short-citcuiting, but it appears to not be EDIT: looks like short-circuiting has nothing to do with the problem.
Also, I put a #try/#catch around this code block because I knew it was exploding every once in a while, but that appears to be ignored (I'm guessing EXC-BAD-ACCESS can't be caught).
So basically I'm wondering if anybody either knows a way I can catch this and throw it out (because I don't care about this error as long as it doesn't make the game crash) or can explain why it might be happening. I know Objective-C does weird things with the "nil" value, so I'm guessing it's pointing to some weird space that is neither an object pointer or nil.
EDIT: Just to clarify, I know the below code is wrong, it's what I was guessing was happening in my program. I was asking if that would cause a problem - which it indeed does. :-)
EDIT: Looks like there is a fringe case that allows you to select an Entity before it gets erased. So, it appears the progression of the code goes like this:
selectedEntity = obj;
NSAutoreleasePool *pool = ...;
[obj release];
if (selectedEntity != nil && etc...) {}
[pool release];
So I'm guessing that because the Autorelease pool has not yet been released, the object is not nil but its retain count is at 0 so it's not allowed to be accessed anyway... or something along those lines?
Also, my game is single-threaded, so this isn't a threading issue.
EDIT: I fixed the problem, in two ways. First, I didn't allow selection of the entity in that fringe case. Second, instead of just calling [entities removeObjectAtIndex:i] (the code to remove any entities that will be deleted), I changed it to:
//Deselect it if it has been selected.
if (entity == selectedEntity)
{
selectedEntity = nil;
}
[entities removeObjectAtIndex:i];
Just make sure you are assigning nil to the variable at the same time you release it, as jib suggested.
This has nothing to do with short circuiting. Objective-C eats messages to nil, so the check for selectedEntity != nil isn't necessary (since messages-to-nil will return NO for BOOL return types).
EXC_BAD_ACCESS is not a catchable exception. It is a catastrophic failure generally caused by trying to follow in invalid pointer.
More likely than not, whatever object selectedEntity points to has been released before the code is executed. Thus, it is neither nil nor a valid object.
Turn on NSZombies and try again.
If your app is threaded, are you synchronizing selectedEntity across threads properly (keeping in mind that, in general, diddling the UI from secondary threads is not supported)?
Your post was edited to indicate that the fix is:
//Deselect it if it has been selected.
if (entity == selectedEntity)
{
selectedEntity = nil;
}
[entities removeObjectAtIndex:i];
This fixes the issue because the NSMutableArray will -release objects upon removal. If the retain count falls to zero, the object is deallocated and selectedEntity would then point to a deallocated object.
if an object (selectedEntity) has been released and dealloc'd it is not == nil. It is a pointer to an arbitrary piece of memory, and deferencing it ( if(selectedEntity!=nil ) is a Programming Error (EXC_BAD_ACCESS).
Hence the common obj-c paradigm:-
[selectedEntity release];
selectedEntity = nil;
i just read this http://developer.apple.com/mac/library/qa/qa2004/qa1367.html which indicated that the error you are getting is a result of over-releasing the object. this means that altough selectedEntity is nill, you released it to many times and it just not yours to use anymore..
Put a breakpoint on OBJC_EXCEPTION_THROW and see where it is really being thrown. That line should never throw a EXC_BAD_ACCESS on its own.
Are you perhaps doing something within the IF block that could cause the exception?
selectedEntity = obj;
NSAutoreleasePool *pool = ...;
[obj release];
if (selectedEntity != nil && etc...) {}
[pool release];
You have a dangling pointer or zombie here. The selectedEntity is pointing at obj which gets releases right before you reference selectedEntity. This makes selectedEntity non-nil but an invalid object so any dereference of it will crash.
You wanted to autorelease the obj rather than release it.