Avatar
The Tumblog of one Jim Dovey, iOS Software Chief Architect at Kobo in Toronto, Ontario.
He Twitters, he has an , and can occasionally be found on LinkedIn or Facebook.
If you have a query, you can ask it here.

This blog contains personal opinions, and is not endorsed by any company.

You can buy Jim's book, Beginning Objective-C, either directly from Apress as an eBook or in print from Amazon:

Likes

Posts tagged Cocoa

Developing for iOS in a Server-Centric World 

Turns out, developing iOS apps is different from developing web apps. Like, hella different. For any server-side readers out there, I thought I’d hit you with a few big ones: There is no CSS. Every part of a design has to be coded in Objective-C.

  • There is no flow layout (like HTML). Everything is position: absolute;.
  • Small “cosmetic changes” can mean hours or days for developers to complete.
  • No one unit tests in Cocoa. Like, no one.
  • Likewise, unit testing is a bitch.
  • No one does automated UI testing. There are some open source projects, but it’s far from the mainstream.

Truth from Mr. Furrow there. As someone who went the other way, I can absolutely say that folks using some of these new server-side frameworks have a ridiculously easy time of it.

Things are starting to change on our side, of course: starting back in the late 80’s with Interface Builder and the Application Kit, and more recently with Cocoa Autolayout. There’s still a world of difference between tweaking a CSS file to change a button’s composition and doing that in Cocoa however.

Fun with Objective-C: Parsing Mathematical Expressions 

funwithobjc:

A while ago, I was looking for a library to parse NSString objects as mathematical expressions. I wanted to be able to take a string like @"2+3*4" and get back 14. I found two easy ways to do this: GCMathParser and NSPredicate (of course!).

GCMathParser is a library by Graham Cox for…

There’s so much awesome in this post that I think I just peed myself.

Luminary: Custom modal UIViewController transitions 

monoceroi:

Just a snippet.

Note: Don’t push or remove view controllers with non-opaque views. The underlying view of the parent view controller is removed.

[CATransaction begin]; CATransition *transition = [CATransition animation];
transition.type = kCATransitionFade;
transition.duration = animated ? 0.5f...

Is it entirely inappropriate for me to say rowr at this point?

Fun with Objective-C: How to learn Cocoa 

funwithobjc:

This is something any experienced Cocoa developer has been asked at least half a dozen times:

“What’s the best way to learn Objective-C/Cocoa?”

I have two answers to this question:

  1. Be curious
  2. Don’t be satisfied

He goes on to finish with the following epithet:

  1. Know what a pointer is.
  2. Memorize the memory management rules.
  3. Never invoke -retainCount.

The second item there is the one I most frequently hear is ‘really difficult’ to understand. It’s not. It’s really not. It looks like this:

  • Only the owner of an object needs to think about its memory management.
  • You only own an object if you get it from a method whose name begins with any one of:
    • alloc, including +allocWithZone:
    • new, including +newSomethingSomething
    • init, including -initWithSomeParameter (er, no, it doesn’t. I’m being stupid. Sorry.)
    • copy, including -copyWithZone: or -mutableCopy or -mutableCopyWithZone:
  • If the object doesn’t come from a method matching those rules, you don’t own it.

Edit: Specifically, the method must either be one of the above words, or begin with one followed by an uppercase letter. This means that +newSomething returns an owned reference, but +newestSomething does not. Thanks to Dave DeLong for reminding me of this via email.

It’s that simple. If you call something including alloc, new, init, or copy, then you must use -release (or -autorelease) to balance that call. If you don’t call one of those methods, you Just Don’t Care.

How about CoreFoundation? That’s even simpler: you own an object if it comes from a method containing Create. The same thing could be said about Copy, but CF’s copy constructors are always careful to frequently already contain Create, so we don’t need to. Anything named using Get returns an already-managed reference, so you don’t need a CFRelease for it.

Edit: I’m reminded by Peter Hosey that many CF-style APIs outside of CoreFoundation itself tend to use Copy without Create, for instance those in CoreGraphics. Note however that not everything that looks like a CF object really is one— many are just C wrappers around Carbon-era C++ code.

See? Easy. A list of four keywords in Objective-C code indicate the only times you need to ever think about memory management. And one keyword in CoreFoundation to tell you the same.

Now, there are exceptions— usually when something missed the boat, or when an existing API needed to be changed to fix an internal memory-management issue. The documentation will tell you about these very rare cases, but the best way to catch them for now is judicious use of Build & Analyze. The Clang compiler’s static analysis tool knows all about these rules, and can be told about any differences to them by any API. It will tell you explicitly if you’ve released something you don’t own, or have failed to release something you do own. Use it. Love it.

Memory management in Cocoa isn’t difficult. There are rules, but they’re simple and easy to remember. The main thing to remember is:

Don’t over-think it

Lesson For Today

So today we had an interesting issue at Kobo: [[NSThread currentThread] threadDictionary] was returning nil. This is never supposed to happen, as it’s created on demand.

After some investigation, we noticed that stack leading to the -layoutSubviews call which resulted in this failure started at +[NSThread exit], going through pthread_exit() and pthread_tsd_cleanup(). This latter function apparently cleaned up a CoreAnimation flag or some such which indicated that a view needed to laid out again, thus causing -layoutSubviews to be called on a background thread, and moreover on a background thread which had already had its Foundation-level context deleted.

This raises the question: why the hell does the documentation for -[UIView setNeedsLayout] not mention that it’s using per-thread flags, thus causing rendering to occur on the same thread which calls this method? Since it sets a flag for CoreAnimation to act upon later, I’d always assumed that said flag would be inspected by the display link on the main thread, not on the current thread.

So, that leads to today’s hard-learned lesson:

Do not call -[UIView setNeedsLayout] on a background thread. Ever.

360|MacDev Paper Submissions

So the folks behind 360|iDev are now putting together a Mac-focussed conference titled 360|MacDev. They put out a call for papers a couple of days ago and I made a few submissions, reproduced below. Do any of these sound interesting, whether presented at the conference or made available separately? Sound off in the comments or you can ping me via Twitter to @alanquatermain if that suits you better.


Inside the Objective-C Runtime

Learn the inner workings of the Objective-C runtime and what you can do with them. Define and modify objects and classes at runtime, generate code, and implement Ruby-style Mixins. Debug system classes by swapping around core methods with your own overrides.


Secret Source: How to use or duplicate Apple’s private functionality

Ever wanted to hook your own data into Apple’s Managed Client infrastructure? Watched Address Book or iPhoto’s integration with the Time Machine user interface in envy? Wished you could implement your own login dialog or account access filters on the Macintosh? Come and See as we open the seventh seal and gaze deep into the workings of some of OS X’s most coveted internal workings.


Power Behind the Throne: The real APIs behind the power of Cocoa

The Cocoa system provides a great deal of power to both new and seasoned developers, but needs must provide a more limited API to maintain its simplicity and grace. This session will look at the other APIs on Mac OS X, showing how Cocoa (probably!) works its magic, teaching you how and when to drop to lower-level APIs to gain more finely-grained control over your application’s interactions with the system.


Parallel Parsers: Tactics for using GCD in your data handling

Grand Central Dispatch has a great many uses, but with some of the common use types it can seem unintuitive to make use of it while parsing a large XML file or traversing a tightly-packed trie. Learn how to break up normally serialized data tasks into concurrent blocks of work while still keeping a close rein on resources and processor activity. At the end of this session we will have a working GCD-based parallel XML parser capable of handling massive blocks of complex XML data in record time!

I imagine some mesh of C Blocks, messages and Go’s channels to play an interesting role. A lot of things that makes Cocoa great are rooted in asynchrony or separation of concerns, and an overriding model could go to town with several of the related concepts.
Jesper makes some guesses about what a new programming language from Apple might look like.

iPhone Development: Greatly Exaggerated 

Jeff brings many of Jon Casasanta’s points down to earth and discovers that, like Mark Twain’s hero, rumours of the death of Mac software have been greatly exaggerated.

Jeff’s main point—the same which leapt immediately to my own mind—is that the most interesting new developer technology is on the Macintosh, not the iPhone. Sure, the iPhone has a more modern user interface setup, all built on top of CoreAnimation for you. That’s just about the limit of it however: the Mac has multi-touch events (NSTouch, anyone?) just like the iPhone, CoreAnimation itself is there, and so much more.

Garbage collection, blocks, and Grand Central Dispatch are all Mac-only (although hopefully the last couple will make an appearance in iPhone OS 4.0? Please?). These are fantastic technologies to play with, and pretty much swung me away from the iPhone. In fact, they’re so important and interesting in so many ways that my forthcoming book, Pro Objective-C for Mac and iPhone, has dramatically more content appropriate to a Macintosh desktop developer than an iPhone developer. There’s just so much more to work with on the Macintosh, even when considering only the Foundation Kit and the runtime.

I don’t doubt that these technologies are going to be made available on the iPhone platform sooner or later; in fact I think it’s inevitable. But they’ll almost always appear on the Macintosh first, so the good Macintosh programmers will be getting the good jobs. Just look at me and Kobo; I didn’t get my position there because I was an iPhone programmer— I got it because I’ve been a Macintosh programmer for many years; I know where the iPhone is now, and I know where it’s likely to be in a few years’ time. So does any Macintosh desktop programmer worth his salt.

So to Jon, Phill and co: as much as you love the iPhone, you ignore the Macintosh at your peril. You owe it to yourselves to learn and work with the newest Macintosh APIs and technologies now, or you’ll be playing catch-up to desktop developers who’ve been refining their arts for a couple of years yet…

More iPhone Background Thoughts

So response to my previous post has been fairly positive, despite not achieving the critical mass necessary to land on Daring Fireball— come on @gruber, pay attention ;o)

I’ve had a few conversations with people over the last week about some of the implementation details and suchlike, and I wanted to expound on the original idea a little. The first post went into some reasonable detail on the security and verification systems, but not so much on the type of processing supported, and how it would be setup in a way beneficial to the goals of both Apple and us developers (or ‘plebs’).

There are a few main areas where background processing of some kind is highly beneficial, for which I will detail some examples here. Maybe I’ll even get the chance to do a third post with some code involved somewhere…

  1. Push Notifications

    This isn’t necessarily what most people would put first, but it’s hard to underestimate just how much of your live data needs can be handled by these magic little packets at once.

  2. Manual Network Updates

    Sometimes push notifications aren’t feasible to implement server-side, or can’t provide enough detailed information (case in point: Outpost). For such applications, the ability to perform some networking on a scheduled basis in the background would be a boon to the applications’ usability.

  3. Custom Notifications

    If you’re writing a to-do list app, or some form of calendar, you’ll probably want to alert the user to certain conditions even when your application isn’t running. Currently the only way to do this is to have a server which manages such notifications and uses APSN to pop up an alert on the user’s iPhone, but the costs for maintaining that service can be prohibitive.

  4. House-Keeping

    If your application deals with large data-sets, it might benefit from performing some house-keeping tasks now and then, for instance database compaction. This is an ideal candidate for a task to run while the phone is locked.

Let’s look at each of these in some detail, so we can see how the setup would work, and how the system would enforce its policies.

Push Notifications

Potential User: Facebook

Your application receives push notifications for new messages as they arrive, but it can’t do anything with that message unless the user chooses the ‘view’ option. If the user cancels the alert, then the application won’t find out about the new message until it does its own networking to fetch the details. A better approach would be to register a background daemon to handle the notifications, thus being able to store them directly into the application’s data store in some manner.

The daemon in this case would run in a no-networking sandbox, since that should be unnecessary for this use case, but would be able to make changes to the disk, subject to the same restrictions as the main application. Once it’s finished processing the incoming notification it can then prompt a standard system response/alert by exiting and returning a special result code which would be monitored by the background processor launchd instance. This way the application can cause the usual alert message to appear, an icon badge to be applied, etc, or it can suppress any standard APSN response action completely.

Manual Network Updates

Potential user: Outpost

In some cases—particularly if an app is based off a third-party service such as Basecamp—it is impossible or impractical to implement push notifications on the server-side, so the application has to do all the legwork at runtime. This can lead to poor user experience issues as the application has to stop and perform a lot of work at startup, when the user wants to just fire it up and check something quickly.

A solution to this would be to register a network download daemon. This would be registered using two key pieces of information: the interval at which it wants to run, and the details of the network resource it wants to access. The system would then tweak the launch times to attempt to coalesce networking operations, meaning that the network hardware would be powered up exactly once, by the system, prior to any such daemons running. The system could also open network connections ready for the daemons, possibly connecting it up to the daemon’s standard input and output streams, further allowing the system to make the major decisions on power and resource management. In this case, the daemon itself might be prohibited from making its own network connections; an alternative should be available however where a daemon could do so, though possibly with a limit on the number of such connections it could open at one time or in a single invocation.

The daemon would be free to do whatever it wished with the data it receives from the network. Those with larger data sets would perhaps simply drop the downloaded data somewhere where the main application could parse it upon launch, perhaps with enough minimal parsing to determine a suitable application icon badge value. Applications with smaller data sets could perform all the parsing internally, updating the application’s main data store directly.

The system would put strict limits on this type of daemon— it can monitor its run time and the amount of CPU and network resources it uses, potentially throttling it or telling it to quit outright once certain limits have been reached.

The system would provide some APIs for this daemon to provide data for an APSN-style alert or other notification to be presented to the user. These APIs would be used to send the data to the parent launchd process, and the application would return a specific result code to inform the service which form of alert (badge, text, sound) to perform after the daemon terminates.

Custom Notifications

Potential user: any to-do list or calendar-based application

Many applications on the App Store now maintain to-do lists or link to online calendar or time-management services. Similar to the manual network type above, it might not be possible or practical for the application developer to build APSN functionality into the service on the server-side, so some means of firing off notifications while the application isn’t running would be necessary to provide full value to your customers.

This type of daemon would be initially registered without any specific launch conditions; these conditions would be added later on, giving specific times at which it would launch. The daemon itself would be expected to only read from the application’s local data store, so it would run in a sandbox with no networking or disk write access, just read access to the application’s data store folders.

This item would in fact be a good candidate for a plugin-style API, similar to those used by Spotlight or QuickLook on the Macintosh. The plugin would be loaded, asked for data, and unloaded when done, and as such wouldn’t require the creation of many separate processes. This might make security and sandboxing a little more problematic to implement however; the best solution would be to spawn a sandboxed loader process for each plugin, but that still requires many of those to be spawned, leaving us only a little better off than using custom daemon processes outright.

House-Keeping

Potential user: OmniFocus

Some applications manage fairly large and complicated data sets; databases in particular are in high demand on the iPhone due to their memory-light access to large amounts of structured data. Every now and then, however, these large data sets might need a little cleaning and pruning. This might be a more involved operation than you want to do while the user is interacting with your application, or it might be something which is good to do frequently (more frequently than your user firing up your app, especially if you’re using any of the other background processing types described above to access your data store).

This type of daemon would be registered with a launch interval specified in days. It would have no access to the network (it’s only working with a local data set after all) but would have read and write access to the main application’s sandbox. The exact launch time would be unspecified, and manageable by the system (to better coalesce multiple such processes together), but would in all likelihood be confined to times when the system is locked, preferably using a heuristic to determine the likelihood of it remaining locked for a good while.

The processes would be monitored for power usage carefully; of all the above, these are perhaps the most likely to cause drain on the system by continually moving data into and out of memory and accessing larger than usual parts of permanent storage. They would also need to have some form of IPC channel available to communicate with the main application so that they can finish up quickly in the event that the application is launched while the daemon is performing its duties. The app would need to prompt the daemon to finish up, then wait for a response back saying that the data store is safe to use. Such interrupted work might then be recommenced when the main application terminates, although that would likely be a function provided and performed by the background launchd instance itself rather than prompted explicitly by the application.

For the IPC, using an Apple-defined ObjC protocol with Distributed Objects would make the most sense, but at present the required runtime support isn’t included in the iPhone’s Foundation framework. An alternative would be a set of Mach IPC methods (defined using MIG) for the application to talk to its daemon via the launchd process itself. The application would talk to launchd, and launchd would pass on messages to the daemon, returning a safe result once the daemon has cleaned up and terminated.

In Summary

The four scenarios above should cover most, if not all, common uses of background processing, while still allowing the system to carefully manage the use of its resources and to optimize such behaviour.

I had planned to push these ideas internally once I started my job at Apple, but since the INS decided to make me its bitch last week, I’m going to have to rely on good old-fashioned social networking to do the job. Perhaps some nice person on the iPhone team will read this and start showing it to the right people. That would be nice. It would help greatly to have it excessively retweeted too— the more people see and advocate such ideas, the more likely they are to materialize.

Now GO TO IT PEOPLE CHOP CHOP kthxbye ;o)

A Blocks Gotcha

So I was just writing some code, and I refactored it a bit by putting a little chunk into a block, then calling that block in multiple places. Here’s the gist original declaration:

NSXMLDocument * (^fetcher)(NSString *) = ^(NSString * typeName) {
    NSArray * arguments = [NSArray arrayWithObjects: ...];

    // fetch the data
    NSXMLDocument * doc = ...;
    if ( doc == nil )
    {
        LogError( ... );
        return ( nil );
    }

    dispatch_async( dispatch_get_main_queue(), ^{
        [progress setDoubleValue: [progress doubleValue] + step];
    });

    return ( doc );
};

Attempting to compile this, however, resulted in the following error from Clang:

error: incompatible block pointer types initializing 'void *(^)(NSString *)', expected
'NSXMLDocument *(^)(NSString *)'
     NSXMLDocument * (^fetcher)(NSString *) = ^(NSString * typeName) {
                                              ^~~~~~~~~~~~~~~~~~~~~~~~

I scratched my head for a while over this, but it all came down to this line:

return ( nil );

It transpires that since MacTypes.h (used by Security in this case) #defines nil as a synonym for NULL, the preprocessor turns that into:

return ( (void *)0 );

Since that’s the first return statement in the block, the compiler creates a block with a void * return type. DOH. The solution was to type-cast the result:

return ( (NSXMLDocument *) nil );

It’s not the most elegant, and it would be nice if MacTypes.h didn’t stomp all over ObjC’s nil data type, but at least it works.

Next page Something went wrong, try loading again? Loading more posts