Is it kosher to use NSNull category trick in order to avoid [NSNull performSelector:...] problems? - objective-c

In our project, we occasionally get our iPhone app to crash when there is something on the network returns JSON with nil in it. Of course, we do have a helper class, which takes care of problems like that. However, people are error-prone and do call objectForKey on NSDictionary instead of our own stringForKey or dateForKey etc.. Now, there is a class to kill all problems like that, once and for all: https://github.com/nicklockwood/NullSafe
My question is: Is NullSafe is really safe? Because sometimes you do want your program to crash if the logic is wrong and you get NSNull. Just ignoring the problem hides it. The app probably will not crash, but, in some cases, will do something weird.
Now I am leaning towards not using this class and just making sure that our JSON NSDictionaries is filtered of all NSNulls BEFORE we try to parse get the values (It could affect performance though).
What do you guys think?

That class is safe in terms of not crashing the application when you send some message to it. It behaves much like nil value.
This class does not solve bugs! If you may get NSNull you should act as it is there and handle that case.
Once I used such class (also because of JSON), but I put NSLog (or ratcher breakpoint) into the -forwardInvocation: method to see from where and why it was called. I wouldn't use this in production.
You also asked about performance. Not sure what takes more: removing NSNulls from an array or searching all classes for their method signatures ;)

Related

Strategy for a self-retaining and self-releasing object

I need to implement a bit of functionality that can be used from a few different places in an application. It's basically sending something over the network, but I don't need it to be attached to any particular view - I can communicate everything to the user by UIAlertViews.
What I would like to do is encapsulating the functionality in an object (?) that can maintain it's own state for a while and then disappear all by itself. I've read in several similar topics that it's generally not advised to have an object that retains and then releases itself, but on the other hand you have singletons which apart from the fact that they never get released, are very similar in nature. You don't need to keep reference to them just to use them properly. In my situation however I feel it woud be somewhat wasteful to create a singleton and then keep it alive for something that takes a few seconds to execute.
What I came up with is a static dictionary local to the class, that keeps unique references to the instances of the class, and then, when an instance is done with its task, it performs selector 'removeObjectForKey' after delay which removes the only existing reference and effectively kills the object. This way I keep only a dictionary in memory which for the most time is empty anyway.
The question is: are there any unexpected side effects of such a solution that I should be aware of and are there any other good patterns for described situation?
So basically instead of a persistent object of your own class, you've got a persistent object of type NSDictionary? How does that help matters? Is your object unusually large? If you are making your codebase more complicated for the sake of a few bytes, that's not a good tradeoff.
Especially now ARC is commonplace, this kind of trickery is usually not a good idea. Have you measured how much memory a singleton approach takes and found it to be a problem? Unless you have done this, use a singleton. It's simpler code, and all other things being equal, simpler code is far better.

Redefine nil in smalltalk to respond any message

I want to redefine smalltalk's nil to work like the one in objective-c. So when nil receives a message that it can't handle, it returns nil. Now I know that nil is just a shortcut for UndefinedObject but is there anything like method_missing in Ruby so I can redefine it in UndefinedObject to always return nil?
The method you are looking for is called doesNotUnderstand: in Smalltalk. You can indeed implement:
UndefinedObject>>doesNotUnderstand: aMessage
^ nil
However, keep in mind that this affects the complete system and might have subtle side effects or introduce bugs in other parts of the system.
Also note that UndefinedObject is not a primitive type, but a normal class inheriting from Object. Therefor nil already understands a large number of messages and might not behave as you would expect coming from Objective-C.
Consider creating your own Null singleton class that implements #doesNotUnderstand: so that you don't modify nil. Make the super class nil (like Object).
Answer something like '^Null instance' instead of '^nil' in cases where you want it.
Null instance badMethod --> nil
If you're the only person who will ever work on this code, I say go for it.
On the other hand, if this is a product owned by some company which is not a synonym for "you", and someone else may at some time have to maintain this, I strongly recommend that you NOT do this. Modifying classes at the heart of Smalltalk is one of THE classic ways to blow your toes off. (I knew a guy once who did this. He was not happy...and always limped a bit after that. Funny old thing, life...).
Share and enjoy.

Getting callbacks of FSPathCopyObjectAsync in ARC

I'm looking to use FSPathCopyObjectAsync and I'm failing. In order to get my head around the problem I've been looking for examples of it elsewhere and although I was experimenting with the slightly dated source code from Matt Long's tutorial over on Cocoa is my Girlfriend, I then found a bit more elaborate example in a project on github, as a category on NSFileManager. Since my project is running under ARC, I tried porting it, and succeeded only at the half of it.
In its current form, the actual copying works, yet the callback method MZCopyFSPathFileOperationStatusProc is never called. That callback method happens to be the sole reason for using asynchronous copying, otherwise one might as well run a synchronous one in the background. I'm assuming the reason for the callback not being called is that some object is incorrectly released by ARC, but there could be something else going on. I am holding on to the return object of the copyItemAsyncAtPath:toPath:destName:options:statusChangeInterval:error: method, so that can't be it, right?
Who can spot the error and explain why this category isn't generating any callbacks? Is it ARC? Is it something else?
Much obliged. EP.
P.S. For redundancy reasons, here is the gist: https://gist.github.com/6f3715753896ccf6fd35
Your delegate needs to be strongly referenced by something. NSFileManager will only hold a weak reference to it (as it should do), so if you don’t have a strong reference to it, your delegate will get released and the callbacks won’t be seen.
Have you considered using blocks for the callbacks? That would probably be preferable.

Encoding URL parameters in Cocoa

I am writing an extension to NSURL that will give it a convenience method URLFromString:withArguments: that builds an URL with some parameters included. The first argument to this method is a string like #"http://www.example.com/foo" and the second is an NSDictionary like {key1 => val1, key2 => val2}, where all of the keys and values are NSStrings. The convenience method will return an NSURL with an URL like, for this example
http://www.example.com/foo?key1=val1&key2=val2
First off, I guess I should ask whether there already exists something like this in Foundation! If not, though, my question is about properly encoding the keys and values. Much has been written on this issue (1, 2, 3). The issues with these three approaches to the problem are, respectively,
Inelegant. (Although it probably works. I haven’t tried it yet.)
Doesn’t properly escape everything.
The source recommends using - stringByAddingPercentEscapesUsingEncoding on an NSString to escape everything. The problem is that this method doesn’t actually escape everything it should, ampersands and slashes being two obvious examples. I don’t know when this method could be useful, given these omissions, but it certainly isn’t useful for my application.
Apparently not kosher with ARC.
I don’t know all that much about ARC yet, but the solution presented on this site uses some CoreFoundation types at which ARC balks. Xcode offers to insert __bridge before a couple of type casts, and the code seems to work then, but I can’t tell whether or not I’m leaking memory or generally doing the Right Thing. And in general it seems to me like I shouldn’t have to go so low-level.
So again, my question is: is there any way to do the percent encoding required for HTTP requests that is built in to NSURL or NSString or the like? And if not, what’s the safest way?
Use (3). ARC doesn't handle CF types directly, just as garbage-collection does not, the bridge casts are just to instruct ARC to take responsibility for the objects from CF (as NSMakeCollectible does for GC). Put in the right bridge casts and you won't be leaking any memory, see section 3.2.4 in the ARC docs

Is asserting that every object creation succeeded necessary in Objective C?

I have recently read Apple's sample code for MVCNetworking written by Apple's Developer Technical Support guru Quinn "The Eskimo!". The sample is really nice learning experience with what I guess are best development practices for iOS development.
What surprised me, coming from JVM languages, are extremely frequent assertions like this:
syncDate = [NSDate date];
assert(syncDate != nil);
and this:
photosToRemove = [NSMutableSet setWithArray:knownPhotos];
assert(photosToRemove != nil);
and this:
photoIDToKnownPhotos = [NSMutableDictionary dictionary];
assert(photoIDToKnownPhotos != nil);
Is that really necessary? Is that coding style worth emulating?
If you're used to Java, this may seem strange. You'd expect an object creation message to throw an exception when it fails, rather than return nil. However, while Objective-C on Mac OS X has support for exception handling; it's an optional feature that can be turned on/off with a compiler flag. The standard libraries are written so they can be used without exception handling turned on: hence messages often return nil to indicate errors, and sometimes require you to also pass a pointer to an NSError* variable. (This is for Mac development, I'm not sure whether you can even turn exception handling support on for iOS, considering you also can't turn on garbage collection for iOS.)
The section "Handling Initialization Failure" in the document "The Objective-C Programming Language" explains how Objective-C programmers are expected to deal with errors in object initialization/creation: that is, return nil.
Something like [NSData dataWithContentsOfFile: path] may definitely return nil: the documentation for the method explicitly says so. But I'm honestly not sure whether something like [NSMutableArray arrayWithCapacity: n] ever returns nil. The only situation I can think of when it might is when the application is out of memory. But in that case I'd expect the application to be aborted by the attempt to allocate more memory. I have not checked this though, and it may very well be that it returns nil in this case. While in Objective-C you can often safely send messages to nil, this could then still lead to undesirable results. For example, your application may try to make an NSMutableArray, get nil instead, and then happily continue sending addObject: to nil and write out an empty file to disk rather than one with elements of the array as intended. So in some cases it's better to check explicitly whether the result of a message was nil. Whether doing it at every object creation is necessary, like the programmer you're quoting is doing, I'm not sure. Better safe than sorry perhaps?
Edit: I'd like to add that while checking that object creation succeeded can sometimes be a good idea, asserting it may not be the best idea. You'd want this to be also checked in the release version of your application, not just in the debug version. Otherwise it kind of defeats the point of checking it, since you don't want the application end user to, for example, wind up with empty files because [NSMutableArray arrayWithCapacity: n] returned nil and the application continued sending messages to the nil return value. Assertions (with assert or NSAssert) can be removed from the release version with compiler flags; Xcode doesn't seem to include these flags by default in the "Release" configuration though. But if you'd want to use these flags to remove some other assertions, you'd also be removing all your "object creation succeeded" checks.
Edit: Upon further reflection, it seems more plausible than I first thought that [NSMutableArray arrayWithCapacity: n] would return nil rather than abort the application when not enough memory is available. Basic C malloc also doesn't abort but returns a NULL pointer when not enough memory is available. But I haven't yet found any clear mention of this in the Objective-C documentation on alloc and similar methods.
Edit: Above I said I wasn't sure checking for nil is necessary at every object creation. But it shouldn't be. This is exactly why Objective-C allows sending messages to nil, which then return nil (or 0 or something similar, depending on the message definition): this way, nil can propagate through your code somewhat similar to an exception so that you don't have to explicitly check for nil at every single message that might return it. But it's a good idea to check for it at points where you don't want it to propagate, like when writing files, interacting with the user and so on, or in cases where the result of sending a message to nil is undefined (as explained in the documentation on sending messages to nil). I'd be inclined to say this is like the "poor man's" version of exception propagation&handling, though not everyone may agree that the latter is better; but nil doesn't tell you anything about why an error occurred and you can easily forget to check for it where such checks are necessary.
Yup. I think it's a good idea.. It helps to filter out the edge cases (out of memory, input variables empty/nil) as soon as the variables are introduced. Although I am not sure the impact on speed because of the overhead!
I guess it's a matter of personal choice. Usually asserts are used for debugging purpose so that the app crashes at the assert points if the conditions are not met. You'd normally like to strip them out on your app releases though.
I personally am too lazy to place asserts around every block of code as you have shown. I think it's close to being a bit too paranoid. Asserts might be pretty handy in case of conditions where some uncertainity is involved.
I have also asked this on Apple DevForums. According to Quinn "The Eskimo!" (author of the MVCNetworking sample in question) it is a matter of coding style and his personal preference:
I use lots of asserts because I hate debugging. (...)
Keep in mind that I grew up with traditional Mac OS, where a single rogue pointer could bring down your entire machine (similarly to kernel programming on current systems). In that world it was important to find your bugs sooner rather than later. And lots of asserts help you do that.
Also, even today I spend much of my life dealing with network programs. Debugging network programs is hard because of the asynchrony involved. Asserts help to with this, because they are continually checking the state of your program as it runs.
However, I think you have a valid point with stuff like +[NSDate date]. The chances of that returning nil are low. The assert is there purely from habit. But I think the costs of this habit (some extra typing, learning to ignore the asserts) are small compared to the benefits.
From this I gather that asserting that every object creation succeeded is not strictly necessary.
Asserts can be valuable to document the pre-conditions in methods, during development, as design aid for other maintainers (including the future self). I personally prefer the alternative style - to separate the specification and implementation using TDD/BDD practices.
Asserts can be used to double-check runtime types of method arguments due to the dynamic nature of Objective C:
assert([response isKindOfClass:[NSHTTPURLResponse class]]);
I'm sure there are more good uses of assertions. All Things In Moderation...