Swift Regex Deep Dive
iOS MacOur introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
Objective-C categories are cool. They allow you do something that you can’t do in most compiled languages: add new methods to existing classes. You can even add methods to classes that you didn’t write.
Suppose you wrote some code to translate an ordinary string, like “Hello, perhaps I could enjoy a bit of your delicious sandwich over there?” to LOLcat speak, like “I can has cheezburger?”
In other languages you would probably subclass the String object and add a member function called -lolspeek
which does the translation. This is kind of lame, though, because you could only call -lolspeek
on string objects that you explicitly create from your subclass. You can’t even do this much in Java because the string class is final, so you couldn’t subclass it anyway.
In a real application you acquire strings from all over the place. They come from text fields. They come from property list files. They come from over the network or via Distributed Objects. It would be nice to be able to lolspeek
any string, no matter where it comes from. Categories come to the rescue:
@interface NSString (BNRLolSpeek)
- (NSString *) lolspeek;
@end // BNRLolSpeek
This category on NSString
makes any NSString
feline-readable, no matter where it originates from.
That’s the cool part. There are some downsides, though. The biggest problem is possible confusion amongst your peers. If you go too crazy adding categories on built-in classes, the people reading your code don’t know if a call they’re looking at is actually built-in or on. It can become harder to share code, too:
“Here, take this method. It’ll do what you want.”
“Uh, NSData
doesn’t have a flobinzate
method.”
“Oh yeah, here’s the category for that”.
“Your NSData category is using an NSString
category?”
“Sorry about that, here’s the NSString
category, as well as this one on NSKeyedArchiver
you’ll be needing”.
Category methods can also have name collisions. Apple has been known to extend their API, and they frequently use the “obvious” name for a new feature. Back in the olden days of Cocoa, around OS X 10.2 and prior, there was no “hidden” property on NSViews
. To hide a view you either had to move it out of the way or remove it from the view hierarchy. It was easy to add a category that added setHidden:
to NSView
to make this work easier. Then OS X 10.3 added setHidden:
as an Apple-provided method, and suddenly things got confused. So what happened?
When your code gets loaded, whether at application launch time, via a plugin, or if you are loaded into another program like a preference pane or screen saver, your categories get loaded too. The Objective-C runtime adds your new methods to the existing classes at this time. If there’s already a method there, it gets replaced. So, if you had a category that included setHidden:
, your setHidden:
replaced Apple’s.
This kind of stuff can lead to subtle and difficult to track down bugs. The kind of embarrassing bugs where you file a Radar and then finally figure out it’s your fault after some back-and-forth with Apple’s engineers.
The solution to both of these problems is to prefix your category methods:
@interface NSString (BNRLolSpeek)
- (NSString *) bnr_lolspeek;
@end // BNRLolSpeek
This way, if for whatever reason Apple adds a lolspeek
method to NSString
, yours won’t clobber it. Also, someone reading code that uses lolspeek
can see immediately that a category method is being used and not get confused that they’re missing out on some Great Apple Functionality in their own code.
Categories are a very powerful, and cool feature of Objective-C, but as you saw here, they can cause problems in unexpected ways if you’re not careful.
(Edit: Dave DeLong brings up a good point that you could use suffixes instead of prefixes – you can use autocomplete without remembering that it’s a custom method, but it still has the “This is a category” tag on it.)
Our introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
The Combine framework in Swift is a powerful declarative API for the asynchronous processing of values over time. It takes full advantage of Swift...
SwiftUI has changed a great many things about how developers create applications for iOS, and not just in the way we lay out our...