Kotan Code 枯淡コード

In search of simple, elegant code

Menu Close

Tag: apple (page 1 of 3)

Protocol Buffers on iOS – Source Code

For those of you who have been asking for the source code to the sample I wrote some time ago illustrating how to serialize and de-serialize protocol buffer messages on the iPhone, then you can download a fully functioning sample project from here:

ProtoPhone

This contains the Xcode project file as well as all of the source code, which should hopefully get you started.

Note that this sample is really just a serialization and de-serialization sample. The code expects for there to be some socket server listening on localhost, so you will have to modify it to no longer expect that (or write your own server that receives ZombieSightinmessages).

Enjoy!

Google Protocol Buffers on iOS and Mac – Redux

In a previous blog post, I talked about how I used the C++ stock Google Protocol Buffers generated code and the native C++ library in my iOS application. It involved some trickery of creating a wrapper Objective-C++ class to keep the C++ from bleeding into my Cocoa project, I had to link a static library, and it actually bloated my application quite a bit.

Since then, I have found a great native Objective-C protobuf implementation that not only plugs into the regular protoc compiler, but it generates ARC-friendly code. Check out this library on Github for the Objective-C protobuf code.

Now, rather than fussing with creating a C++ object (which requires me to manually malloc and free!), I can just create a new protobuf object that feels natural and native to my iOS and Mac code:

ZombieSighting *sighting =
        [[[[[[[ZombieSighting builder] setDescription:@"This is a zombie"]
                setLatitude:21.007]
                setLongitude:18.214]
                setZombieType:ZombieTypeFast]
                setName:@"Lord Kevin of the Undead"] build];

With this implementation of protobufs, I can just do [sighting data] to get the NSData for the object, and I can de-serialize a protobuf object that I plucked off the wire far more easily than before:

DirectMessage *dm = [DirectMessage parseFromData:data];

See how much easier and cleaner everything is? The moral of the story here is good enough isn’t good enough. Just because you find one solution doesn’t mean it’s the best one. I am constantly in search of simpler, easier, more elegant ways of doing things and I think I’ve finally found a decent way of dealing with protobufs in Objective-C.

Sending Protocol Buffer Messages from iOS to a Socket Server

In a previous blog post, I took a look at how to create an Akka socket server using Akka IO that would read incoming messages in the form of Google Protocol Buffers. The information on the wire was framed so that it contained the length of the protobuf message as well as a numeric identifier telling my server which protobuf message.

Using a Scala client was a decent way of debugging things to figure out if my server code worked properly, but my real goal was to be able to send messages from an iPhone or iPad application to the Akka socket server. I continued to use the zombie sighting message that I created for the Akka server and for my “ProtoPhone” sample from this blog post here.

Now what I need to do is write some code in Objective-C that will send the protobuf messages over TCP via socket streams to the Akka server. The following code is not production ready, it’s just a brute force way of making sure that it works. In a real-world scenario there would be much more error handling, I wouldn’t send bytes on the NSStream until I got the “space available” message, etc.

NSInputStream *inputStream;
    NSOutputStream *outputStream;

    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;
    CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"localhost", 9999, &readStream, &writeStream);
    inputStream = (__bridge_transfer NSInputStream *)readStream;
    outputStream = (__bridge_transfer NSOutputStream *)writeStream;

    [inputStream setDelegate:self];
    [outputStream setDelegate:self];

    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

   // [inputStream open];
    [outputStream open];

    // Flip bytes for network order prior to transmission
    uint32_t length = (uint32_t)htonl([_rawZombie length]);
    uint32_t messageType = (uint32_t)htonl(1);

    // Keeping track of bytes written for debug purposes...
    int bytesWritten;
    bytesWritten = [outputStream write:(uint8_t *)&length maxLength:4];
    NSLog(@"Wrote %d bytes to the stream", bytesWritten);
    bytesWritten = [outputStream write:(uint8_t *)&messageType maxLength:4];
    NSLog(@"Wrote %d bytes to the stream", bytesWritten);

    // Write contents of protobuf object serialized as string, loaded into NSData pointer
    bytesWritten = [outputStream write:(uint8_t *)[_rawZombie bytes] maxLength:[_rawZombie length]];
    NSLog(@"Wrote %d bytes to the stream", bytesWritten);

    [outputStream close];

This is pretty much all there is to it. As I mentioned, there’s some refactoring that needs to happen in order to deal with things like error handling and to better handle situations when I have to use multiple writes to send a single object (e.g. not enough space available on the stream), but you get the general idea.

I will be posting more on this as I go along, but for now, I am plenty happy with my shiny new toys of being able to communicate between an iOS client and an Akka server.

Why Apple GameCenter is Still Annoying for Developers

Ever since GameCenter and GameKit (the SDK for GameCenter) were made available for iOS and subsequently made available for OS X developers, there has been an explosion of new games on the market. Some of this is due to GameCenter, but most of this is due to the simple fact that the App Store is the single largest and cheapest supply channel to get games from developers to consumers.

One thing has always bothered me when developing with GameKit – your application must be configured in iTunes Connect before any of the GameCenter functionality is available. For those not all that familiar with the process of developing applications for iOS there are two stages of the development process. The first stage is where your application is registered on the iOS Developer Portal. This means creating an AppID, a provisioning profile, certificates, and the other information necessary to develop and test your application on a real device. Since Xcode 4, this process has been streamlined considerably and isn’t quite the nail-biting, hair-pulling source of agony it used to be. (Don’t get me wrong, though, it’s not all roses and perfume either).

The second stage, if you are to believe Apple’s documentation, tutorials, rhetoric, and propaganda, is the publication stage. It is during this stage that you go over to the iTunes Connect website and configure your application for publication. Here, you create a new app, which consists of picking an existing AppID, and then supplying multiple pages of information in a very intimidating, “this will go on your permanent record” kind of experience.

So, what’s wrong with these two stages and GameCenter? I’ll tell you – you can’t develop with GameKit until your application is in iTunes Connect. Developers, especially agile developers, like to fire up Xcode, get in there and start coding stuff up, poking around, molding the clay, as it were. They do not want things slowing them down, and ITC slows them down and, for many indie developers, has actually scared them off to the point where the developers skip GameCenter entirely and roll their own (not that rolling your own isn’t an idea without merit, but that’s a topic for another blog post).

What this boils down to is that if you’re going to create a GameCenter-enabled game for the iPhone, immediately after you create your empty scaffolding “hello world” application from a bare bones template, you have to perform the following steps:

  • Go to the iOS Developer Portal and create an AppID for your application (e.g. com.kotancode.AwesomeGameThatNobodyWillEverPlay)
  • If you want to test this on a device, you need to create and download a provisioning profile for that AppID. This isn’t all that big a deal, and is necessary with or without game kit programming.
  • Now the fun part: go to iTunes connect and supply bogus values for all of the following:
    • Name, AppID
    • Availability date – you probably want to set this for 1 year from now
    • Pricing tier
    • Version
    • Copyright
    • Primary and Secondary Categories
    • Answer 10 multiple choice questions on content used to determine the rating for the game.
    • Description
    • Keywords
    • Support, Marketing, Privacy Policy URLs
    • Your contact information
    • Review notes – this is where I typically put the phrase – “going through the motions of creating an ITC profile for my app just so I can get GameCenter to work. Don’t accept or review this application. If you get tired of seeing messages like this, maybe you should let GameKit devs develop their test versions without an ITC app.”
    • Supply a large app icon (no, I’m not kidding, and all these screenshots need to be in a specific PPI density and resolution)
    • Supply at least one 3.5-inch Retina screenshot
    • Supply at least one 4-inch Retina screenshot
    • Supply at least one iPad screenshot

Now, and only now, after you have supplied all this information and wasted your time by creating an ITC application (thankfully you can choose to upload your application later and don’t need to upload a fully running app first.. that would be even more ludicrous than this process), can you finally do a simple task such as obtain a pointer to an authenticated GKLocalPlayer object.

So here’s the bottom line: Want your game players to be part of Apple’s ecosystem of friends, leaderboards, badges, and get limited multiplayer (turn-based or real-time locally over bluetooth) with chat capabilities? Then you’re going to have to suck it up and jump through all of Apple’s hoops. For many, many developers, this initial crapshoot is worth it for what they get in return.

For other developers, even indie developers, who are going to be providing a backing infrastructure for their application anyway, creating a private store for badges, achievements, accomplishments, friends, and multiplayer may be the way to go.

All this frustration aside, if you already have placeholder screenshots (which can be solid color blocks), then the whole process probably takes 20 minutes to do, so you can get up and running in one night. My problem isn’t that this takes too long, it’s that it’s so annoying, and even at times difficult to decipher, that it turns off newbie developers who would otherwise want to play with GameCenter.

Using Attributed Strings in iOS6

The title of this blog post should read something like “Hallelujah!” or “It’s about freaking time!” because this feature is long, long, long overdue. Way back in iOS 3.2, Apple allowed the NSAttributedString class to creep into the iOS SDK from the main Mac tool kit. However, none of the UI controls contained any support for rendering these attributed strings.

So, if you wanted to write your own code that read through attributed strings and manually created the various subviews and view configurations necessary for rendering, you were welcome to do so. Of course, this was a colossal pain in the ass and only those people building applications whose sole source of income relied on the use of these things ever tried it.

Now, with iOS6, the pain is gone and we have built-in support for attributed strings. What does that mean? It means that I can create a multi-color piece of text and set it on a label rather than having to create one label for each color like I would normally have done in hackish fashion on previous versions of the SDK.

NSMutableAttributedString *mutableString = [[NSMutableAttributedString alloc] initWithString:@"ThisIsAttributed"];
[mutableString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0,4)];
[mutableString addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor]  range:NSMakeRange(5,2)];
[mutableString addAttribute:NSForegroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(6,10)];

So what does this do? Well, it will produce an attributed string that has the word “This” in red, “is” in blue, and “Attributed” in green.

Instead of setting label text directly the way you’re used to doing with just label.text=@”foo” , now you use a new property called attributedText.

Try it out and enjoy your new freedom. The following are a list of the attributes that come with iOS 6 and attributed strings:

  • NSFontAttributeName – UIFont
  • NSParagraphStyleAttribute – NSParagraphStyle
  • NSForegroundColorAttributeName – UIColor
  • NSBackgroundColorAttributeName – UIColor
  • NSLigatureAttributeName – NSNumber ( 0 -no ligatures, 1 – default ligatures )
  • NSKernAttributeName – NSNumber (0 kerning disabled)
  • NSStrikeThroughStyleAttributeName – NSNumber
  • NSUnderlineStyleAttributeName – NSNumber
  • NSStrokeColorAttributeName – UIColor, default nil
  • NSStrokeWidthAttributeName – NSNumber
  • NSShadowAttributeName – NSShadow, nil default
  • NSVerticalGlyphFormAttributeName – NSNumber , 0 horizontal text, 1 vertical text

Teach Yourself Mac OS X Lion Application Development in 24 Hours – Code

For those few of you who have not yet posted a horrible review of my book, Teach Yourself Mac OS X Lion Application Development in 24 Hours, I have attached the code for this book. Apparently there has been an issue with the publisher not actually hosting the code the way they should or in the location they were supposed to use … so below is a link to a ZIP file that contains the raw, unedited, source code that I used to build the book. All of these samples were tested and ran on OS X Lion before the book was published.

Teach Yourself Lion in 24 Hours – Code

Enjoy.

Getting the Android Emulator to Work on the Macbook Pro Retina Display

Recently I posted about my thoughts on the first impression left by the Android SDK using Eclipse and the ADT Plugin for Eclipse (this is the “traditional route” of Android developers). My first impression was less than stellar.

So I wondered if the inherent crappiness in this was due to Windows or just that overall patchwork, cobbled together Rube Goldberg feeling you get when working with certain open source projects above a certain size. So, I pulled out the Macbook Pro (a 2012 retina display model, the retina display will play a key factor in my impression) and went through the process of installing the SDK.

The Android SDK installs just fine on OS X Mountain Lion and Eclipse “Juno” installed just fine as well. I had trouble with the SSL URL for the developer tools that many books and Google themselves give you, and even had trouble just removing the S from HTTP in the URL, having to decipher what the plugin URL was for the non-SSL download. Really, they could make that process a crapload easier. Again, I had this problem both on Windows and Mac, so the suck was cross-platform.

After finally getting all of the various pieces of the puzzle installed on the Mac, I went through the process of creating an Android Virtual Device (AVD). I started the emulator and noticed that it showed up in a big window but was only drawing on a small portion of it. It didn’t seem to respond to mouse-clicks.

I wasted hours of my life “troubleshooting” this issue, checking everything from memory issues to bad APIs to re-installing the SDK. After a while of swearing and pounding the forehead against the desk, I noticed that it actually did respond to mouse-clicks, but in empty areas of the window. A button that was in the bottom of the drawn portion would respond in the bottom of the larger, empty window. A-HA!

I then thought:

I’ll bet the retina display’s annoying scaling crap is actually confusing the emulator.

Turns out I was right. The emulator is using a deprecatedabsurdly old piece of code that is unaware of situations when the pixels being drawn are not in the same place as the pixels being displayed. I could either wait for Google to fix this (really Google, this is inexcusable in a non-beta, shipping product. Open source or no, this is bull****) or I could settle for a temporary workaround.

That temporary workaround is a tool I found called SetResX. This tool allows you to set real resolution not the annoying “best for retina” and “not so best for retina” user-friendly options you get with the Mountain Lion and Lion settings dialogs. All you need to do is pick any resolution big enough to support a 1:1 pixel-faithful resolution of your emulated screen (e.g. I picked 1680×1050 to support my emulated tablet’s 1080p HD resolution) and you can then run the emulator without the bizarre side-effects.

So, what this highlights in my experience are two things, in order of suckiness:

  1. Shame on Google for releasing non-beta, shipping tools that use deprecated, out-of-date API calls that are incompatible with any Mac retina display.
  2. Shame on Apple for their Macbook Pro Retina display. They release it and without an external tool like SetResX, you can’t actually access all of the pixels the monitor is capable of, you just get scaled and obscured versions. This is a little disappointing, really. It’s my damn computer, don’t pretend to know what’s best for me and hide all of the possible resolutions the card/monitor is capable of from me. Apple used to typically allow developers to get around such “we know what’s best for you” assumptions with standard Unix command-line tools, but there is no such stock tool in this case.

So, if you have a Retina Display Macbook Pro and you want to do some Android development off-device, you’re going to need a tool that futzes with your resolution, or, you can actually hook your laptop up to a non-retina monitor and slide the emulator window onto that monitor and you no longer have an issue (because the non-retina monitor has a 1:1 pixel faithful copy).

In my quest for things that follow the kotan (elegant simplicity) philosophy, my experience with the Android toolset is that it eschews both elegance and simplicity.

Upgraded my iPhone to a Nokia Lumia 900 Windows Phone

Nokia Lumia 900

Nokia Lumia 900

Those of you who have been following my blog and my tweets know that I’m something of a polyglot and polyphone – I program in many different languages and I’ve used many different phones. I used the Palm Pre and it’s unified contacts and messaging systems years ago, before such a feature was even a twinkle in the eye of either Apple or Microsoft. I’ve owned and developed for the original iPhone, the 3, the 3G, the 4, and the 4S. I’ve owned an iPad 1, an iPad 2, and “the new iPad formerly called the iPad 3”. I’ve owned the Samsung Windows Phone and now own the Nokia Lumia 900.

The first thing to notice about the Lumia 900 is that it is big. It’s not just that it looks big, but it feels big. It’s heavier than the iPhone and takes up substantially more palm space. Back when I first held one of the Lumias in my hands, I was originally turned off by this – the last thing I wanted was a bigger phone. Now that I’ve had a chance to use the phone for more than just a quick in-store demo, I have completely changed my mind on that. The size, weight, and overall feel of this device is absolutely perfect.

The next thing I noticed about this phone is that it’s fast. Not just kinda fast or faster than my iPhone but it is blazingly fast. No matter what I do I can’t get any of the UI to skip, jitter, pause, or have any of the other weird issues that my Samsung used to have. Couple that with the brilliant, giant display and this phone is a freaking joy to use.

Even with all of iOS’ recent advances, I still hate the walled-off silo feeling you get from each application where even the ones that have been modified to work together still feel like a hack. This is in stark contrast to the smooth, effortless way I can sift through Facebook, LinkedIn, and Twitter updates from all of my contacts in a single place. As mentioned in previous blog posts, Windows Phone is designed specifically to get out of my way and give me what I want, when I want it, in an elegantly minimalist way.

Specific to the Nokia is the “Nokia Blue” color scheme, which is by far my favorite of any of the stock color options. Other things specific to the Nokia are a pile of awesome ring tones and notification sounds that are far better than the stock Microsoft options. Finally, the other thing that Nokia did that they deserve huge credit for is the “App Highlights” app.

I mentioned in a previous blog post that the state of the Windows Phone marketplace is disgusting at the moment. It is littered with crap, more crap, porn, some more crap, first party games, and a few gems struggling to shine in a sea of even more crap. Nokia has human curators who troll the marketplace and find the best of the best, the stuff we’re all looking for but don’t know we’re looking for it how to find it. Until the Marketplace gets better, I’ll be using the App Highlights app to find new stuff, not the Marketplace. I trust Nokia’s curators more than I do the automated ranking/relevance algorithm currently screwing the marketplace.

Something that Windows Phones have been doing for a while now that no iOS device does is bluetooth audio text-to-speech reading aloud of your incoming text messages. In addition, you can dictate outbound text messages, which makes for an awesome experience in a car that has bluetooth. I can make and receive calls and texts smoothly using nothing but audio and speech controls. The Lumia has this feature the same as other Windows Phone 7+ devices.

If you are an “app addict” like so many iOS users, where your smart phone experience has nothing to do with the phone and everything to do with the apps, then you may still find Windows Phone lacking. However, if you actually want to use the “smart” in your “smart phone”, then you’ll not find a better device than the Nokia Lumia 900.

Initial thoughts on the new iPad

Yesterday I received an early birthday present, a white 32GB WiFi iPad 3. To give you some proper background, I have owned at least one of all generations of the iPhone except the current 4s (the “s” being for “Siri”). I have also owned a first-generation iPad and, until yesterday, my sole tablet device was an iPad 2. I love my iPad 2. I use it for nearly everything that I can and only resort to the laptop when I plan on doing many hours of writing or if I need to do some actual coding. In other words, you can pry my iPad from my cold, dead hands.

When the “shiny new” iPad was announced my first reaction was “meh”. I really wasn’t all that impressed. Sure, it had a shiny new retina display but the difficulty Apple has to overcome isn’t convincing people that an iPad is awesome, it’s convincing owners of an iPad 2 that an iPad 3 is awesome enough to warrant forking over what I believe is a flaming truckload of cash. While these things are awesome, the only reason I can even condone purchasing one for myself is that they are tax deductions for my freelance development business and technical writing.

Case in point – I wouldn’t buy it for myself, it had to be given to me as an early birthday present. So, is the hype on the iPad 3 worth it?

The first thing I noticed when I unboxed the new iPad is that it’s heavy. Typically you have to put new devices on a scale to notice the different in weight but, even just holding one iPad in either hand, it’s very obvious that the new iPad weighs a bit more. It’s not enough so that it’s going to stop me from using it but it does have a more noticeable heft to it.

The next thing I noticed was that when setting up the new iPad, it asked me if I wanted to enable dictation. Dictation? I’d never seen this option on the iPad 2 and I didn’t remember hearing about it in the rumor mill. As a writer, the idea of getting dictation services on my iPad is pretty appealing. While dictation is there, iPad 3 has no “Siri” on it, which is fine by me. In another blog post, I will post a review of the dictation ability from an author’s point of view rather than just someone wanting to dictate an e-mail message.

Everyone raves about the new horsepower of the device – it has a better processor in it with more cores blah blah… For most applications that I tried I couldn’t tell the difference between how they ran on the iPad 2 and how they ran on the new device. The only ones that showed noticeable differences were the higher-end apps like 3d games and video streaming apps. A large portion of what I use my iPad for is watching video so this is a good thing for me. I’ve actually seen some videos of people doing speed tests where the iPad 2 comes out ahead in most situations. My experience is that the 3 has a much better display and is no slower, and visibly faster in video rendering, so that’s a plus.

All in all I’m really happy with the device and can’t wait to try out the dictation feature – of course you can’t use dictation on a train or a plane without annoying your neighbors so I wonder about where I might be able to use it. Is the new iPad 3 worth all the hype? Maybe, it’s an upgrade but a minor one. Is it worth the money? I don’t think so, but that hasn’t stopped me from owning it 🙂

iOS and Mac OS X Convergence Continues with Mountain Lion

Just the other day, Apple announced the major features coming up in their new operating system release, Mac OS X Mountain Lion. Before going into details on Mountain Lion, it’s worth remembering here that less than a year ago, Apple released Lion, which included a host of features that it borrowed from the iPad, including Popovers, the option to use “natural” scrolling the way you do on the iPad, iOS-style invisible scroll bars, iCloud support, full-screen applications, and even some great new enhancements for developers using Objective-C.

So what is Apple planning to do with Mac OS X Mountain Lion? According to the information I can find publicly, here are some of the highlights:

  • Game Center – Apple’s game service that provides everything from matchmaking to leader boards, achievements, and even in-game multiplayer voice chat is coming to the Mac. This also means that developers writing games for the Mac will be able to participate in all that amazing goodness that iOS developers have been enjoying since iOS 4.1.
  • iCloud – I don’t really know all the details here only that iCloud is even more integrated into the OS now and I’m assuming the developer experience around iCloud is getting better. I’m actually hoping that experience gets better because writing iCloud code on Lion is a pain in the ass.
  • Sharing – More iOS goodness comes to the Mac with sharing “sheets”. Every application on Mountain Lion now gets a little sharing icon that uses sharing services, allowing you to share whatever you’re looking at in the application with your buddies via e-mail or whatever other services are registered on the Mac, including Twitter. I would imagine that it wouldn’t take much work, assuming the sharing APIs are good, to add other sharing targets like Facebook, Dropbox, LinkedIn, etc to your Mac – turning it into just as much of a social hub as your phone.
  • Twitter – Twitter is a first-class citizen on the Mac just like it became first-class on iOS 5. This means that Mountain Lion users can tweet from pretty much anywhere and using the “sharing” services, they can share pretty much whatever they’re working on in any application (that supports it) via Twitter. Not only is twitter a first-class citizen, but applications can send Tweets on behalf of their users without any extra work. Twitter appears to be accessible in API form to developers without them having to figure out which of the 10 open-source Objective-C twitter libraries they want to shoehorn into their app. This is fantastic news for developers and I hope we get similar integration possibilities with Facebook, Dropbox, etc via Sharing “sheet” APIs.
  • Notifications – In what looks to be very similar to the notification center on iOS 5, Apple now has a unified display of messages that are pertinent to the user, including IMs, iMessages (also now a fully integrated part of Mountain Lion), and application-level notifications. In classic Apple style, they are aiming to push popular 3rd parties out of this market with their 1st party offering. Applications like Growl may find it hard to compete with the unified interface, but time will tell how the 1st-vs-3rd party battles are settled.
  • Gatekeeper – Again I don’t know all the details, but this feature aims to make your application more secure and, more importantly, provides developers with a secure way of distributing verified, signed applications outside the app store. For most developers, the App Store is absolutely the best way to go. But for some applications, it makes no sense to put in the app store and many people don’t need Apple’s distribution channel and so aren’t comfortable sharing 30% of their profit with the company. Gatekeeper and Developer IDs and signing give developers a way of distributing applications that users can feel comfortable downloading, installing, and using.
  • 64-Bit – You simply cannot run Mountain Lion on a 32-bit machine. The kernel is 64-bit and an entire host of 32-bit “wrappers” are missing in Mountain Lion, further drawing a line in the sand against 32-bit apps. If only some other software giant whose name starts with M that makes an operating system would also draw a similar line. In words from one of my favorite movies of all time (Zombieland), “It’s time to nut up or shut up.”
  • SSO – In order to support seamless sharing and such, there appears to be some kind of single sign-on facility in OS X much like Windows has been allowing you to link your “LiveID” to your user account for quite some time … only with the Twitter integration I would imagine Apple’s SSO allows for more than just Apple ID storage.

All in all Mountain Lion is looking pretty promising. Again, there’s absolutely nothing groundbreaking in here, but starting with Lion and continuing with Mountain Lion, it appears that Mac developers are finally getting access to the same amount of lovin’ that the iOS developers have been enjoying since iOS 4.