@objc creates a wrong class name in Objective-C

A few months ago, I decided I'd get started porting SDCAlertView to Swift, but I was only a few minutes in until I ran into a problem I had no idea how to solve: I couldn't get my class names right in both Swift and Objective-C. Even though there are copious amounts of documentation covering the interoperability of Swift and Objective-C, somehow I couldn't get it to work and I brushed it off as me being stupid.

Tonight I tried again, and after some more research it turned out that the behavior I saw was actually a bug in the compiler! I'm surprised that the latest Xcode version is 6.1.1 and that apparently not enough people have run into this problem for Apple to make it a priority.

The bug can easily be reproduced by creating an Objective-C project in Xcode, and then adding the following Swift class:

1
2
3
4
5
import UIKit

@objc(SDCMyLabel)
class MyLabel: UILabel {
}

You would expect that, once you import MyProject-Swift.h in your Objective-C class, you could instantiate a class named SDCMyLabel. However, instead, you can only instantiate a class named MyLabel.

I found this very recent Stack Overflow question which pretty much asks the same thing. "milos" gives a great answer by explaining the observed behavior in Xcode 6.0.1, and the expected behavior according to the WWDC session video.

After reading the answer and watching the relevant parts of the vide, I slightly changed my previously-drawn conclusion from "I'm stupid" to "Xcode's stupid" and filed rdar://19261044. If you're running into the same problem, please duplicate and cross your fingers the engineers at the fruit company will fix it soon.

Dev-only iPhones

With today's release of iOS 8.1, most app developers are looking at 4 significantly different iOS versions they will be supporting: iOS 7.0., iOS 7.1, iOS 8.0, and iOS 8.1. Factoring in the number of devices (iPhone 4S, iPhone 5, iPhone 5s, iPhone 6, and iPhone 6 Plus) that run these OS versions, there is a grand total of 16 different configurations. That's without even counting the iPhone 5c, which is internally pretty much the same as the 5, or the rumored iOS 8.2 and iOS 8.3 updates.

Assuming an average off-contract price of $400 for these models, that means you're looking at $6,400 for 1 set of iPhones used for development. Creating a universal app? Your total will now exceed $10,000.

So now you have these 16 phones that will in most cases be used for testing maybe a handful of apps, that have chips and software functionality in them that will be used very little (if at all), and will most of the time just sit in some desk drawer with a dead battery. I could think of better ways to spend money.

This problem could have a very simple solution: dev-only iPhones. Remove or disable the cellular chip (you can simulate cellular networks using the Network Link Conditioner), give it an 8GB storage chip, remove apps such as Weather, Stocks, Calculator, Clock, etc., disable the App Store for all but the developer's own apps, allow any supported iOS version to be installed using Xcode, and sell at-cost, but only to developers in the iOS Developer Program.

By disabling cellular and dumbing the OS down to only include parts that developers can interact with, it becomes pretty useless for people who are just trying to look for a sweet deal on an iPhone/iPod touch. The win for developers is that they only need 1 of each device, but they're also cheaper.

You could even take it a step further and set memory, CPU and screen size limits (meaning only use 4" of the available 5.5"), allowing you to simulate an iPhone 5s on an iPhone 6 Plus. Now developers only need to buy the iPhone 6 Plus to be mostly covered, though I'd still recommend also getting an iPhone 5 or iPhone 5c for 32-bit devices.

I may be way off course here due to technical implications or limitations that I'm not aware of. There are also still cases in which you'd need an actual device on the actual software as consumers use it. Developers don't always need to test against every iOS version on every supported iOS device. But for developers who do and don't want to spend the money on all these different devices, a dev-only iPhone may be exactly what they need.

UIMenuController and the responder chain

The responder chain is a very important paradigm in the world of iOS development, and not terribly hard to understand. Dozens of articles have been written about it, and with some examples, the concept of finding a responder to a certain event by traversing a chain of potential responders is fairly straight-forward.

But today it completely threw me off. The goal was very simple and has been done many times before: showing a label whose text can be copied to the clipboard. Having never worked with UIMenuController, I fired up Google and of course found an excellent NSHipster article near the top.

I did as the article said. I created my UILabel subclass (only accepting copy: as an action it can perform), added my gesture recognizer, and configured and showed the UIMenuController. It worked, but instead of only showing the Copy menu item, it also showed the Select All item.

Well, that's weird. I implemented canPerformAction:withSender: like this:

1
2
3
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    return action == @selector(copy:);
}

I made sure that this method really only returned YES for the Copy item, proceeded to explicitly return NO for selectAll: and, when that failed as well, even changed the implementation of this method to just return NO for any item. But Select All doesn't take NO for an answer, and it stubbornly showed up anyway! I was baffled and could not get rid of this Select All item.

I did some research, and learned that UIMenuController uses the responder chain to figure out what items to show. Furthermore, the documentation for canPerformAction:withSender: read:

This default implementation of this method returns YES if the responder class implements the requested action and calls the next responder if it does not.

That would explain the problem, if it weren't for the fact that Select All was the only other item that showed. Cut, Paste, Select, etc. did not. What was so special about Select All that no matter what I did, it always decided to make an unwanted appearance?

Finally I saw it. One of the last methods of the view controller that created this label had a method named, you guessed it, selectAll:. I didn't immediately connect the dots, but at least renaming that method to selectAllContacts: (which was a better name for that method anyway) got rid of Select All.

But how? I returned NO from my label's canPerformAction:withSender: for all actions except copy:. This means that for all other actions (see the informal UIResponderStandardEditActions), the next responder in the chain would be called. And (if necessary) the next, and the next.

At some point, my view controller, which participates in the responder chain, became the first responder and returned YES for the selectAll: action, simply because the method was implemented and part of UIResponderStandardEditActions.

So if implementing a method in that protocol is all that's needed to show the corresponding menu item, that would mean that implementing canPerformAction:withSender: in my UILabel subclass was unnecessary. I removed the method altogether and sure enough, the Copy menu item was still there. Problem solved.

Xcode & Objective-C Oddities

Any developer that has worked with Xcode to write a little more than just "Hello, World" knows that Xcode and Objective-C have their quirks. Chances are you have heard of @TextFromXcode, the Twitter handle that portrays Xcode as a high school bully in fake text conversations like this:

Xcode Bully

But it's not always Xcode that makes Apple platform developers sometimes frown and sigh. Sometimes it's the developers themselves, sometimes it's the documentation, and sometimes a hidden gem from within Apple frameworks makes an appearance. I've compiled a short list of things I've encountered. Because it's Sunday and I didn't have anything better to do.

UIGobblerGestureRecognizer

Say what? A "gobbler" recognizer? Does it recognize when the user imitates a turkey? Well, maybe, but according to BJ Homer, it is used to avoid recognition of a gesture while animations are in progress. Ah of course! Now the name "gobbler" makes perfect sense! 😶

UITapAndAHalfRecognizer

Speaking of gesture recognizers, there's another remarkable one that lives in the private section of UIKit: UITapAndAHalfRecognizer. This is a private subclass of UIGestureRecognizer that records "a tap and a half".

So what does that mean? Does it detect whether the user goes in for a second tap, but never actually touches the screen? Or does the user touch the screen ever so slightly that the second tap can hardly be considered a complete tap? Nope! This recognizer fires when a second tap stays on the screen. Not sure for what functionality Apple needs this, but it's been around since at least iOS 4, so it probably has a purpose.

Naming is hard

There are only two hard things in Computer Science: cache invalidation and naming things.
- Phil Karlton

Naming is hard, but Objective-C developers always say that verbosity is one of Objective-C's strengths because its naming conventions are self-documenting. Normally I'd agree, but in this case, I think Apple may want to consider a different name.

HMCharacteristicValueLockMechanismLastKnownActionUnsecuredUsingPhysicalMovementExterior is a brand new constant in iOS 8 and has got to be one of the longest constants that's available in iOS. Try saying it without taking a breath in the middle.

I found it in the iOS 8 API diffs, but it did make me wonder. What is the longest Objective-C method available in Cocoa Touch? Well, a quick Google search led to a blog post by Stuart Sharpe, who used the Objective-C runtime to generate a list of methods in the iOS 7 SDK.

Turns out, the longest method in the iOS 7 SDK is

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
+[CUIShapeEffectStack shapeEffectSingleBlurFrom:
                               withInteriorFill:
                                         offset:
                                       blurSize:
                                   innerGlowRed:
                                 innerGlowGreen:
                                  innerGlowBlue:
                               innerGlowOpacity:
                                 innerShadowRed:
                               innerShadowGreen:
                                innerShadowBlue:
                             innerShadowOpacity:
                                   outerGlowRed:
                                 outerGlowGreen:
                                  outerGlowBlue:
                               outerGlowOpacity:
                                 outerShadowRed:
                               outerShadowGreen:
                                outerShadowBlue:
                             outerShadowOpacity:
                            hasInsideShadowBlur:
                           hasOutsideShadowBlur:]

Unless iOS 8 introduces a longer method name, this one takes the cake with 22 arguments and 352 characters. If you have Xcode configured to line-break at 80 characters (yes, some people still do that), this method signature alone, without any arguments, takes up 5 lines.

Another beauty of a method lives in Core Animation and its method signature is

1
- [CAMediaTimingFunction functionWithControlPoints::::]

::::? Is that even valid syntax? Yes, and you call the method like this:

1
[CAMediaTimingFunction functionWithControlPoints:0.25 :.50 :0 :1.0];

Was an array really too much to ask...?

[NSDate nilDate]

This one has made the rounds throughout the developer community before, but I'm adding it here in case you haven't seen it yet. Try running the following code:

1
2
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar components:NSCalendarUnitYear fromDate:nil toDate:[NSDate date] options:0];

In the console log, you'll find the following output:

*** -[__NSCFCalendar components:fromDate:toDate:options:]: fromDate cannot be nil
I mean really, what do you think that operation is supposed to mean with a nil fromDate?
An exception has been avoided for now.
A few of these errors are going to be reported with this complaint, then further violations will simply silently do whatever random thing results from the nil.

Either a grumpy Apple developer woke up at the wrong side of the bed or has a great sense of humor. In any case, I wouldn't mind if more sarcastic warnings started popping up in Xcode's console.

Defying the Uncertainty Principle in iOS

[I]n 1927, Werner Heisenberg stated that the more precisely the position of some particle is determined, the less precisely its momentum can be known, and vice versa.
Wikipedia

If that's true, and it's fairly safe to assume that it is, I'd avoid using -[CLLocation speed] for apps like radar detectors. I wonder if we're ever going to get a -[CLSpeed location] method, which has a more accurate speed and a less accurate location.

Xcode at it again

Lastly, the following is a screenshot I personally took at work that completely baffled me.

This would not go away, even after cleaning the build folder and rebuilding. In the end I resolved the problem by running

1
2
$ git stash
$ git reset --hard HEAD

Then, after a clean build and git stash pop the errors finally went away...

That's just a few things I've found while working with Xcode and Objective-C over the years. If you have more, please share!

Objective-C prefixes: a thing of the past?

This past week, there was, again, a lot to do about Objective-C and prefixing. To most iOS developers, the story sounds familiar: one camp is strongly in favor, another camps is strongly against, and a third camp couldn't really care less.

Unless I'm unaware of any other platforms where the discussion was also a hot topic, this time I was at least a little responsible for instigating a debate that will never see a clear winner, with the following tweet:

Let's first clear up that Swift doesn't need to have class prefixes, because it has built-in support for namespacing through modules. From what I read, earlier Xcode 6/Swift betas did not have module support, but at least we know it's coming before 1.0 hits.

However, this doesn't solve any of the problems Objective-C has, and so it was surprising to see this field was removed when creating a new Objective-C project. You can still set this prefix per project after you create it, but since most Xcode templates create source files for you, those files will be created without a prefix.

I noticed the lack of this option, as well as the lack of a file template for Objective-C categories, back in beta 2 and immediately filed two bugs. The missing file template is as of this writing still open, but the class prefix got closed a few days later. Normally, radars aren't known for their wealth of information related to the issue the radar was filed for, but Apple Engineering made an exception this time.

After much deliberation, engineering has removed this feature.

This was removed intentionally. We are no longer encouraging the use of prefixes for app code, and for frameworks, you can create a prefix in the Project Inspector after creating the project.

Okay, so no more prefixes for app code. Didn't see that coming. Does Apple now encourage developers to start making extensive use of frameworks?

No. If you want to use a prefix, you can set one in the project inspector. Especially for frameworks, this is easy since the template creates no source files that should be prefixed. If you really want to prefix the classes in your main app binary, you might need to rename the few that are created initially, but the recommendation is generally that frameworks should use prefixes (in Obj-C, not in Swift) to avoid namespace issues, and apps generally don't need to.

The key part here is in the last few words: "don't need to".

Third-party libraries, especially frameworks that don't ship with the source code, need a prefix, because the chances of naming collisions with other code or, even worse, other libraries is significant. Users of the libraries can't (and even if they can, are likely not willing to) change the name of your classes because they collide with some other library's code.

"App code" on the other hand, is very unique to one particular app. It contains the UI and some of the business logic that puts your app together. Most view controllers, for example, are app code. App code is not likely to be reused, because it's very specific in what it does and is therefore unlikely to collide with other classes (assuming you name your classes well). If you think "well, this functionality may be reused in some other project", it's a great candidate for a framework!

I was always a big fan of the class prefixes, and while it was sometimes hard to come up with what prefix to use, I've come to actually like how they look, too. Classes that don't have a prefix feel like they're missing something. However, the guideline of "prefix frameworks, not app code" does make sense, so I will start using that from now on as well.