Quantcast
Channel: NSHipster
Viewing all 382 articles
Browse latest View live

NSLocale

$
0
0

Internationalization is like flossing: everyone knows they should do it, but probably don't.

And like any habit, it becomes second-nature with practice, to the point that you couldn't imagine not doing it. All it takes is for someone to show you the way.

Let NSHipster be your dental hygienist Virgil through these foreign lands.. without all of the lecturing about tooth decay (promsies!)

i18n versus l10n

As is necessary in any discussion about Internationalization (i18n) or Localization (l10n), we must take some time to differentiate the two:

  • Localization is the process of adapting your application for a specific market, or locale.
  • Internationalization is the process of preparing your app to be localized.

Internationalization is a necessary, but not sufficient condition for localization, and will be the focus of this article. Localization, which involves the translation of text and assets into a particular language, will be covered in a future edition of NSHipster.

What makes internationalization difficult is having to think outside of your cultural context. All of the assumptions you have about the way things are supposed to work must be acknowledged and reconsidered. You have to fight the urge to write off things that may seem trivial, like sorting and collation, and empathize with the pain and confusion even minor differences may cause.

Fortunately for us, we don't have to do this alone. Meet NSLocale:

NSLocale

NSLocale is a Foundation class that encapsulates all of the conventions about language and culture for a particular locale. A locale encompasses all of the linguistic and cultural norms of a particular group of people, including:

  • Language
  • Keyboards
  • Number, Date, and Time Formats
  • Currency
  • Collation and Sorting
  • Use of Symbols, Colors, and Iconography

Each locale corresponds to a locale identifier, such as en_US, fr_FR, ja_JP, and en_GB, which include a language code (e.g. en for English) and a region code (e.g. US for United States).

Locale identifiers can encode more explicit preferences about currency, calendar system, or number formats, such as in the case of de_DE@collation=phonebook,currency=DDM, which specifies German spoken in Germany, using phonebook collation, and using the pre-Euro Deutsche Mark.

Users can change their locale settings in the "Langauge & Text" (or "International" on older versions of OS X) System Preferences on the Mac, or "General > International" in iOS Settings.

Language & Text System Preferences

Formatting Dates & Numbers

Although NSLocale encapsulates a rich set of domain-specific information, its typical usage is rather understated.

If there's just one thing you should learn about NSLocale, it's that you should always pass [NSLocale currentLocale] into your NSDateFormatter and NSNumberFormatter instances. Doing this will ensure that dates, numbers, and currencies will be formatted according to the localization preferences of the user.

Actually, make that a meta lesson about locales: always use NSDateFormatter and NSNumberFormatter when displaying anything to do with dates or numbers, respectively.

But let's get back to some of the cool features of NSLocale itself, shall we?

-objectForKey:

NSLocale typifies Foundation's obsession with domain-specific pedantry, and nowhere is this more visible than in -objectForKey:. Cue the list of available constants:

  • NSLocaleIdentifier
  • NSLocaleLanguageCode
  • NSLocaleCountryCode
  • NSLocaleScriptCode
  • NSLocaleVariantCode
  • NSLocaleExemplarCharacterSet
  • NSLocaleCalendar
  • NSLocaleCollationIdentifier
  • NSLocaleUsesMetricSystem
  • NSLocaleMeasurementSystem
  • NSLocaleDecimalSeparator
  • NSLocaleGroupingSeparator
  • NSLocaleCurrencySymbol
  • NSLocaleCurrencyCode
  • NSLocaleCollatorIdentifier
  • NSLocaleQuotationBeginDelimiterKey
  • NSLocaleQuotationEndDelimiterKey
  • NSLocaleAlternateQuotationBeginDelimiterKey
  • NSLocaleAlternateQuotationEndDelimiterKey

While this all may seem like fairly esoteric stuff, you may be surprised by the number of opportunities your application has to use this information to make for a better user experience.

It's the small things, like knowing that quotation marks vary between locales:

English: “I can eat glass, it doesn't harm me.”
German: „Ich kann Glas essen, das tut mir nicht weh.“
Japanese:「私はガラスを食べられます。それは私を傷つけません。」

So if you were building a component that added quotations around arbitrary text, you should use NSLocaleQuotationBeginDelimiterKey and NSLocaleAlternateQuotationEndDelimiterKey rather than assuming @"\"" for English quotation marks.

-displayNameForKey:value:

Another impressive, albeit mostly-useless method is -displayNameForKey:value:, which can return the display name of a locale identifier (NSLocaleIdentifier):

NSLocale*frLocale=[[NSLocalealloc]initWithLocaleIdentifier:@"fr_FR"];NSLog(@"fr_FR: %@",[frLocaledisplayNameForKey:NSLocaleIdentifiervalue:@"fr_FR"]);NSLog(@"en_US: %@",[frLocaledisplayNameForKey:NSLocaleIdentifiervalue:@"en_US"]);

frFR: français (France)
en
US: anglais (États-Unis)

You should use this method any time you need to display information about the user's current locale, or any alternative locales available to them, like in this screen from the Settings app:

Languages Settings

+preferredLanguages

One final method worth mentioning is NSLocale +preferredLanguages, which returns an array of IETF BCP 47 language identifier strings, in order of user preference.

An app that communicates with a web server can use these values to define the Accept-Language HTTP header, such that the server has the option to return localized resources:

NSMutableURLRequest*request=...;[requestsetValue:[NSStringstringWithFormat:@"%@",[[NSLocalepreferredLanguages]componentsJoinedByString:@", "]],forHTTPHeaderField:@"Accept-Language"];

Even if your server doesn't yet localize its resources, putting this in place now will allow you to flip the switch when the time comes, without having to push an update to the client. Neat!


Internationalization is often considered to be an un-sexy topic in programming--just another chore that most projects don't have to worry about. In actuality, designing software for other locales is a valuable exercise (and not just for the economic benefits of expanding your software into other markets).

One of the greatest joys and challenges in programming is in designing systems that can withstand change. The only way designs can survive this level of change is to identify and refactor assumptions about the system that may not always hold. In this way, internationalization represents the greatest challenge, making us question everything about our cultural identity. And in doing so, we become not just better programmers, but better people, too.

So go and be a better person: make NSLocale part of your daily ritual.


UIAccessibility

$
0
0

We all want to help one another, human beings are like that. - Charlie Chaplin

You know what I wish everyone would copy from Apple? Their assistive technologies.

iPhones and iPads--magical as they are--become downright life-changing for individuals with disabilities and their families because of Apple's commitment to accessibility. Look no further than the WWDC 2012 Introduction Video, which opens with Per Busch, a blind man who walks the woods of Kassel, Germany with the aid of Ariadne GPS. It's a lovely reminder of the kind of impact our work can have on others.

Accessibility, like internationalization, is one of those topics that's difficult to get developers excited about. But as you know, NSHipster is all about getting developers excited about this kind of stuff. Let's get started:


UIAccessibility is an informal protocol in UIKit that provides accessibility information about user interface elements. This information is used by VoiceOver and other assistive technologies to help users with disabilities interact with your application.

All of the standard views and controls in UIKit implement UIAccessibility, so applications are accessible by default. As a result, the task of improving the accessibility of your application is one of minor adjustments rather than wholesale re-implementation.

Here's a list of all of the properties in UIAccessibility:

  • accessibilityLabel
  • accessibilityHint
  • accessibilityValue
  • accessibilityLanguage
  • accessibilityTraits
  • accessibilityFrame
  • accessibilityActivationPoint
  • accessibilityElementsHidden
  • accessibilityViewIsModal

Enabling Accessibility

Before we go any further, take a couple minutes to play with VoiceOver, and understand how accessibility information is conveyed to the user. Open the Settings app, tap General, scroll to the bottom and tap Accessibility. In Accessibility, you'll see settings for assistive technologies grouped by category: Vision, Hearing, Learning, and Physical & Motor.

Tap VoiceOver, and then tap the VoiceOver switch to turn it on. An alert will pop up telling you that enabling VoiceOver changes the way you control your device. Dismiss the alert, and now VoiceOver is now enabled on your device.

Don't Panic--unlike setting your device to another language, there's no real risk of not being able to figure out how to turn VoiceOver off.

VoiceOver Settings

Using the device in VoiceOver mode is a bit different than you're used to:

  • Tap once to select an item
  • Double-Tap to activate the selected item
  • Swipe with three fingers to scroll

Press the Home button and start exploring!

You'll notice that all of the stock Apple apps--Messages, Calendar, Weather--each is fully-usable in VoiceOver mode. Heck, even Camera is usable, with VoiceOver telling you where faces are in your camera's viewport!

By contrast (perhaps), try some of the apps you've downloaded from the App Store. You may be surprised that some (but certainly not all) of the most visually-stunning apps, with all of their custom controls and interactions are completely unusable in this mode.

So now that you have an idea of what you're working with, let's talk about implementation:

Label & Hint

If there was just one thing you could do to improve the accessibility of your app, paying attention to accessibility labels and hints of UI elements would be it.

Accessibility labels and hints tell VoiceOver what to say when selecting user interface elements. This information should be helpful, but concise.

  • accessibilityLabel identifies a user interface element. Every accessible view and control must supply a label.
  • accessibilityHint describes the results of interacting with a user interface element. A hint should be supplied only if the result of an interaction is not obvious from the element's label.

The Accessibility Programming Guide provides the following guidelines for labels and hints:

Guidelines for Creating Labels

If you provide a custom control or view, or if you display a custom icon in a standard control or view, you need to provide a label that:

  • Very briefly describes the element. Ideally, the label consists of a single word, such as Add, Play, Delete, Search, Favorites, or Volume.
  • Does not include the type of the control or view. The type information is contained in the traits attribute of the element and should never be repeated in the label.
  • Begins with a capitalized word. This helps VoiceOver read the label with the appropriate inflection.
  • Does not end with a period. The label is not a sentence and therefore should not end with a period.
  • Is localized. Be sure to make your application available to as wide an audience as possible by localizing all strings, including accessibility attribute strings. In general, VoiceOver speaks in the language that the user specifies in International settings.

Guidelines for Creating Hints

The hint attribute describes the results of performing an action on a control or view. You should provide a hint only when the results of an action are not obvious from the element’s label.

  • Very briefly describes the results. Even though few controls and views need hints, strive to make the hints you do need to provide as brief as possible. Doing so decreases the amount of time users must spend listening before they can use the element.
  • Begins with a verb and omits the subject. Be sure to use the third-person singular declarative form of a verb, such as “Plays,” and not the imperative, such as “Play.” You want to avoid using the imperative, because using it can make the hint sound like a command.
  • Begins with a capitalized word and ends with a period. Even though a hint is a phrase, not a sentence, ending the hint with a period helps VoiceOver speak it with the appropriate inflection.
  • Does not include the name of the action or gesture. A hint does not tell users how to perform the action, it tells users what will happen when that action occurs.
  • Does not include the name of the control or view. The user gets this information from the label attribute, so you should not repeat it in the hint.
  • Is localized. As with accessibility labels, hints should be available in the user’s preferred language.

Traits

If you are using custom controls, or have taken liberties with non-standard use of a standard control, you should make sure to specify the correct accessibility traits.

Accessibility traits describe a set of traits that characterize how a control behaves or should be treated. Examples include distinctions like:

  • Button
  • Link
  • Search Field
  • Keyboard Key
  • Static Text
  • Image
  • Plays Sound
  • Selected
  • Summary Element
  • Updates Frequently
  • Causes Page Turn
  • Not Enabled
  • None

The accessibilityTraits property takes a bitmask of UIAccessibilityTraits values, which can be combined in ways specified in the documentation.

For example, if a custom button control displays an image and plays a sound when tapped, you should define the traits for "Button", "Image", and "Plays Sound". Or, if you were to use a UISlider for purely decorative purposes, you should set the "Not Enabled" trait.

Frame & Activation Point

As a general rule, the cleverness of a custom UI element is directly proportional to how gnarly its implementation is. Overlapping & invisible views, table view hacks, first responder shenanigans: sometimes it's better not to ask how something works.

However, when it comes to accessibility, it's important to set the record straight.

accessibilityFrame and accessibilityActivationPoint are used to define the accessible portions and locations of UI elements, without changing their outward appearance.

As you try out your app in VoiceOver mode, try interacting with all of the elements on each screen. If the selection target is not what you expected, you can use accessibilityFrame and accessibilityActivationPoint to adjust accordingly.

Value

Accessibility value corresponds to the content of a user interface element. For a label, the value is its text. For a UISlider, it's the current numeric value represented by the control.

Want to know a quick way to improve the accessibility of your table views? Try setting the accessibilityValue property for cells to be a localized summary of the cell's content. For example, if you had a table view that showed status updates, you might set the accessibilityLabel to "Update from #{User Name}", and the accessibilityValue to the content of that status update.


Apple has done a great service to humanity in making accessibility a first-class citizen in its hardware and software. You're missing out on some of the best engineering, design, and technical writing that Apple has ever done if you ignore UIAccessibility.

Do yourself a favor and read the excellentAccessibility Programming Guide for iOS. It only takes an hour or two to get the hang of everything.

Who knows? You may end up changing someone's life because of it.

NSCharacterSet

$
0
0

As mentioned previously, Foundation boasts one of the best, most complete implementations of strings around.

But a string implementation is only as good as the programmer who wields it. So this week, we're going to explore some common uses--and misuses--of an important part of the Foundation string ecosystem: NSCharacterSet.


If you're fuzzy on what character encodings are (or even if you have a pretty good working knowledge), you should take this opportunity to read / re-read / skim and read later Joel Spolsky's classic essay "The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)". Having that fresh in your mind will give you a much better appreciation of everything we're about to cover.

NSCharacterSet and its mutable counterpart, NSMutableCharacterSet, provide an object-oriented way of representing sets of Unicode characters. It's most often used with NSString& NSScanner to filter, remove, or split on different kinds of characters. To give you an idea of what those kinds of characters can be, take a look at the class methods provided by NSCharacterSet:

  • alphanumericCharacterSet
  • capitalizedLetterCharacterSet
  • controlCharacterSet
  • decimalDigitCharacterSet
  • decomposableCharacterSet
  • illegalCharacterSet
  • letterCharacterSet
  • lowercaseLetterCharacterSet
  • newlineCharacterSet
  • nonBaseCharacterSet
  • punctuationCharacterSet
  • symbolCharacterSet
  • uppercaseLetterCharacterSet
  • whitespaceAndNewlineCharacterSet
  • whitespaceCharacterSet

Contrary to what its name might suggest, NSCharacterSet has nothing to do with NSSet.

However, NSCharacterSetdoes have quite a bit in common with NSIndexSet, conceptually if not also in its underlying implementation. NSIndexSet, covered previously, represents a sorted collection of unique unsigned integers. Unicode characters are likewise unique unsigned integers that roughly correspond to some orthographic representation. Thus, a character set like NSCharacterSet +lowercaseCharacterSet is analogous to the NSIndexSet of the integers 97 to 122.

Now that we're comfortable with the basic concepts of NSCharacterSet, let's see some of those patterns and anti-patterns:

Stripping Whitespace

NSString -stringByTrimmingCharactersInSet: is a method you should know by heart. It's most often passed NSCharacterSet +whitespaceCharacterSet or +whitespaceAndNewlineCharacterSet in order to remove the leading and trailing whitespace of string input.

It's important to note that this method only strips the first and last contiguous sequences of characters in the specified set. That is to say, if you want to remove excess whitespace between words, you need to go a step further.

Squashing Whitespace

So let's say you do want to get rid of excessive inter-word spacing for that string you just stripped of whitespace. Here's a really easy way to do that:

NSString*string=@"Lorem    ipsum dolar   sit  amet.";string=[stringstringByTrimmingCharactersInSet:[NSCharacterSetwhitespaceCharacterSet]];NSArray*components=[stringcomponentsSeparatedByCharactersInSet:[NSCharacterSetwhitespaceCharacterSet]];components=[componentsfilteredArrayUsingPredicate:[NSPredicatepredicateWithFormat:@"self <> ''"]];string=[componentscomponentsJoinedByString:@" "];

First, trim the string of leading and trailing whitespace. Next, use NSString -componentsSeparatedByCharactersInSet: to split on the remaining whitespace to create an NSArray. Next, filter out the blank string components with an NSPredicate. Finally, use NSArray -componentsJoinedByString: to re-join the components with a single space. Note that this only works for languages like English that delimit words with whitespace.

And now for the anti-patterns. Take a gander at the answers to this question on StackOverflow.

At the time of writing, the correct answer ranks second by number of votes, with 58 up and 2 down. The top answer edges it out with 84 up and 24 down.

Now, it's not uncommon for the top-voted / accepted answer to not be the correct one, but this question may set records for number of completely distinct answers (10), and number of unique, completely incorrect answers (9).

Without further ado, here are the 9 incorrect answers:

  • "Use stringByTrimmingCharactersInSet" - Only strips the leading and trailing whitespace, as you know.
  • "Replace ' ' with ''" - This removes all of the spaces. Swing and a miss.
  • "Use a regular expression" - Kinda works, except it doesn't handle leading and trailing whitespace. A regular expression is overkill anyway.
  • "Use Regexp Lite" - No seriously, regular expressions are completely unnecessary. And it's definitely not worth the external dependency.
  • "Use OgreKit" - Ditto any other third-party regexp library.
  • "Split the string into components, iterate over them to find components with non-zero length, and then re-combine" - So close, but componentsSeparatedByCharactersInSet: already makes the iteration unnecessary.
  • "Replace two-space strings with single-space strings in a while loop" - Wrong and oh-so computationally wasteful.
  • "Manually iterate over each unichar in the string and use NSCharacterSet -characterIsMember:" - Shows a surprising level of sophistication for missing the method that does this in the standard library.
  • "Find and remove all of the tabs" - Thanks all the same, but who said anything about tabs?

I don't mean to rag on any of the answerers personally--this is all to point out how many ways there are to approach these kinds of tasks, and how many of those ways are totally wrong.

String Tokenization

Do not use NSCharacterSet to tokenize strings.
Use CFStringTokenizer instead.

You can be forgiven for using componentsSeparatedByCharactersInSet: to clean up user input, but do this for anything more complex, and you'll be in a world of pain.

Why? Well, remember that bit about languages not always having whitespace word boundaries? As it turns out, those languages are rather widely used. Just Chinese and Japanese--#1 and #9 in terms of number of speakers, respectively--alone account for 16% of the world population, or well over a billion people.

...and even for languages that do have whitespace word boundaries, tokenization has some obscure edge cases, particularly with compound words and punctuation.

This is all to say: use CFStringTokenizer (or enumerateSubstringsInRange:options:usingBlock:) if you ever intend to split a string by words in any meaningful way.

Parse Data From Strings

NSScanner is a class that helps to parse data out of arbitrary or semi-structured strings. When you create a scanner for a string, you can specify a set of characters to skip, thus preventing any of those characters from somehow being included in the values parsed from the string.

For example, let's say you have a string that parses opening hours in the following form:

Mon-Thurs:  8:00 - 18:00
Fri:        7:00 - 17:00
Sat-Sun:    10:00 - 15:00

You might enumerateLinesUsingBlock: and parse with an NSScanner like so:

NSMutableCharacterSet*skippedCharacters=[NSMutableCharacterSetpunctuationCharacterSet];[skippedCharactersformUnionWithCharacterSet:[NSCharacterSetwhitespaceCharacterSet]];[hoursenumerateLinesUsingBlock:^(NSString*line,BOOL*stop){NSScanner*scanner=[NSScannerscannerWithString:line];[scannersetCharactersToBeSkipped:skippedCharacters];NSString*startDay,*endDay;NSUIntegerstartHour,startMinute,endHour,endMinute;[scannerscanCharactersFromSet:[NSCharacterSetletterCharacterSet]intoString:&startDay];[scannerscanCharactersFromSet:[NSCharacterSetletterCharacterSet]intoString:&endDay];[scannerscanInteger:&startHour];[scannerscanInteger:&startMinute];[scannerscanInteger:&endHour];[scannerscanInteger:&endMinute];}];

We first construct an NSMutableCharacterSet from the union of whitespace and punctuation characters. Telling NSScanner to skip these characters greatly reduces the logic necessary to parse values from the string.

scanCharactersFromSet: with the letters character set captures the start and (optional) end day of the week for each entry. scanInteger similarly captures the next contiguous integer value.

NSCharacterSet and NSScanner allow you to code quickly and confidently. They're really a great combination, those two.


NSCharacterSet is but one piece to the Foundation string ecosystem, and perhaps the most misused and misunderstood of them all. By keeping these patterns and anti-patterns in mind, however, not only will you be able to do useful things like manage whitespace and scan information from strings, but--more importantly--you'll be able to avoid all of the wrong ways to do it.

And if not being wrong isn't the most important thing about being an NSHipster, then I don't want to be right!

Ed. Speaking of (not) being wrong, the original version of this article contained errors in both code samples. These have since been corrected.

UICollectionView

$
0
0

UICollectionView is the new UITableView. It's that important.

This is not to say that collection views are in any way unknown or obscure--anyone who went to any of the WWDC sessions about it, or got to play with in the iOS 6 beta already know what's up.

Remember, being an NSHipster isn't just about knowing obscure gems in the rough. Sometimes, it's about knowing about up-and-comers before they become popular and sell out. So before everybody else finds out for themselves, here's the skinny on the next big thing:


UICollectionView takes the familiar patterns of UITableView and generalizes them to make any layout possible (and, in many cases, trivial).

Like UITableView, UICollectionView is a UIScrollView subclass that manages a collection of ordered items. Items are managed by a data source, which provides a representative cell view at a particular index path.

Unlike UITableView, however, UICollectionView is not constrained to a vertical, single-column layout. Instead, a collection view has a layout object, which determines the position of each subview, similar to a data source in some respects. More on that later.

Cell Views

In another departure from the old-school table view way of doing things, the process of recycling views has been significantly improved.

In -tableView:cellForRowAtIndexPath:, a developer had to invoke the familiar incantation:

UITableViewCell*cell=[tableViewdequeueReusableCellWithIdentifier:...];if(!cell){cell=[[UITableViewCellalloc]initWithStyle:...reuseIdentifier:...];}

UICollectionView thankfully does away with this. -dequeueReusableCellWithReuseIdentifier:forIndexPath: is guaranteed to return a valid object, by creating a new cell if there are no cells to reuse. Simply register a UICollectionReusableView subclass for a particular reuse identifier, and everything will work automatically. Thankfully, this behavior has been backported to UITableView as well with iOS 6.

Supplementary Views

Because collection views aren't relegated to any particular structure, the convention of "header" and "footer" views isn't really applicable. So in its place, collection views have supplementary views, which can be associated with each cell.

Each cell can have multiple supplementary views associated with it--one for each named "kind". As such, headers and footers are just the beginning of what can be done with supplementary views.

The whole point is that with supplementary views, even the most complex layout can be accomplished without compromising the semantic integrity of cells. UITableView hacks are to spacer.gif as UICollectionView cells are to semantic HTML.

Decoration Views

In addition to cell views and supplementary views, collections also have decoration views. A decoration view, as the name implies, is something that without a functional purpose... other than to perhaps spurn the hatred of anti-skeuomorphic zealots across the interwebs. But really, if you're resigned to imbue your virtual book collection app with immaculately-textured wood-grained shelves, it might as well be easy to do, right?

One thing to remember about decoration views is that they are entirely managed by the layout, unlike cell or supplementary views, which are under the jurisdiction of the collection view data source.

Layouts and Layout Attributes

Layouts are at the heart of what makes UICollectionView so magical. Think of them as the CSS to your semantic HTML of collection cells from before.

UICollectionViewLayout is an abstract base class for positioning cell views and their supplementary and decoration views. But rather than subclass this directly, most applications will opt to use or subclass UICollectionViewFlowLayout. Flow layouts cover the broad class of layouts with some notion of linearity, whether that's a single row or column or a grid.

Until you're comfortable enough to understand the limitations of flow layouts, it's generally a safe bet to just start with that.

Each cell view, supplemental view, and decoration view have layout attributes. To get an idea of how flexible layouts are, look no further than the properties of an UICollectionViewLayoutAttributes object:

  • frame
  • center
  • size
  • transform3D
  • alpha
  • zIndex
  • hidden

Attributes are specified by the kind of delegate methods you might expect:

  • -layoutAttributesForItemAtIndexPath:
  • -layoutAttributesForSupplementaryViewOfKind:atIndexPath:
  • -layoutAttributesForDecorationViewOfKind:atIndexPath:

What's extremely cool is this method here:

  • -layoutAttributesForElementsInRect:

Using this, you could, for example, fade out items as they approach the edge of the screen. Or, since all of the layout attribute properties are automatically animated, you could create a poor-man's cover flow layout in just a couple lines of code with the right set of 3D transforms.

In fact, collection views can even swap out layouts wholesale, allowing views to transition seamlessly between different modes--all without changing the underlying data.


Since the introduction of the iPad, there has been a subtle, yet lingering tension between the original UI paradigms of the iPhone, and the demands of this newer, larger form factor. With the iPhone 5 here, and a rumored "iPad mini" on the way, this tension could have threatened to fracture the entire platform, had it not been for UICollectionView (as well as Auto-Layout).

There are a million ways Apple could (or could not) have provided this kind of functionality, but they really knocked it out of the park with how they designed everything.

The clean, logical separation between data source and layout; the clear division between cell, supplementary, and decoration views; the extensive set of layout attributes that are automatically animated... a lot of care and wisdom has been put together with these APIs.

As a result, the entire landscape of iOS apps will be forever changed. With collection views, the aesthetic shift that was kicked off with the iPad will explode into an entire re-definition of how we expect apps to look and behave.

Everyone may not be hip to collection views quite yet, but now you'll be able to say that you knew about them before they were cool.

Lest you think you have to hold off for iOS 6 adoption to catch up in order to use collection views in your app, here's some great news:

Peter Steinberger has released PSTCollectionView, a 100% API-compatible replacement for UICollectionView that supports iOS 4.3+. Check it out!

#pragma

$
0
0

#pragma declarations are a mark of craftsmanship in Objective-C. Although originally used to make source code compatible between different compilers, the Xcode-savvy coder uses #pragma declarations to very different ends.

In this modern context, #pragma skirts the line between comment and code. As a preprocessor directive, #pragma evaluates at compile-time. But unlike other macros, such as #ifdef...#endif, the way #pragma is used will not change the runtime behavior of your application. Instead, #pragma declarations are used by Xcode to accomplish two primary tasks: organizing code and inhibiting compiler warnings.

Organizing Your Code

Code organization is a matter of hygiene. How you structure your code is a reflection on you and your work. A lack of convention and internal consistency indicates either carelessness or incompetence--and worse, makes a project difficult to maintain and collaborate on.

Good habits start with #pragma mark. Like so:

@implementationViewController-(id)init{...}#pragma mark - UIViewController-(void)viewDidLoad{...}#pragma mark - IBAction-(IBAction)cancel:(id)sender{...}#pragma mark - UITableViewDataSource-(NSInteger)tableView:(UITableView*)tableViewnumberOfRowsInSection:(NSInteger)section{...}#pragma mark - UITableViewDelegate-(void)tableView:(UITableView*)tableViewdidSelectRowAtIndexPath:(NSIndexPath*)indexPath{...}

Use #pragma mark in your @implementation to divide code into logical sections. Not only do these sections make it easier to read through the code itself, but it also adds visual cues to the Xcode source navigator (#pragma mark declarations starting with a dash (-) are preceded with a horizontal divider).

Xcode Sections

If your class conforms to any @protocols, start by grouping all of the methods within each protocol together, and adding a #pragma mark header with the name of that protocol. Another good convention is to group subclassed methods according to their respective superclass. For example, an NSInputStream subclass should have a group marked NSInputStream, followed by a group marked NSStream. Things like IBAction outlets, or methods corresponding to target / action, notification, or KVO selectors probably deserve their own sections as well.

Your code should be clean enough to eat off of. So take the time to leave your .m files better than how you found them.

Inhibiting Warnings

#pragma mark is pretty mainstream. On the other hand, #pragma declarations to inhibit warnings from the compiler & static analyzer--now that's pretty fresh.

You know what's even more annoying than poorly-formatted code? Code that generates warnings. Especially 3rd-party code. There are few things as irksome as that one vendor library that takes forever to compile, and finishes with 200+ warnings. Even shipping code with 1 warning is in poor form.

Pro tip: Try setting the -Weverything flag and checking the "Treat Warnings as Errors" box your build settings. This turns on Hard Mode in Xcode.

But sometimes there's no avoiding compiler warnings. Deprecation notices and retain-cycle false positives are two common situations where this might happen. In those rare cases where you are absolutely certain that a particular compiler or static analyzer warning should be inhibited, #pragma comes to the rescue:

// completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.#pragma clang diagnostic push#pragma clang diagnostic ignored "-Warc-retain-cycles"self.completionBlock=^{...};#pragma clang diagnostic pop

This code sample from AFNetworking (contributed by Peter Steinberger) is an example of an otherwise unavoidable warning from the static analyzer. Clang notices a strong reference to self within the block, and warns about a possible retain cycle. However, the super implementation of setCompletionBlock takes care of this by nil-ing out the strong reference after the completion block is finished.

Fortunately, Clang provides a convenient way to get around all of this. Using #pragma clang diagnostic push/pop, you can tell the compiler to ignore certain warnings, only for a particular section of code (the original diagnostic settings are restored with the final pop).

You can read more about the LLVM's use of #pragma in the Clang Compiler User's Manual.

Just don't use this as a way to sweep legitimate warnings under the rug--that will only come back to bite you later.


So there you go: two ways you can markedly improve your code using #pragma declarations.

Like the thrift store 8-track player you turned into that lamp in the foyer, #pragma remains a curious vestige of the past: Once the secret language of compilers, now re-purposed to better-communicate intent to other programmers. How delightfully vintage!

@

$
0
0

Birdwatchers refer to it as (and I swear I'm not making this up) "Jizz": those indefinable characteristics unique to a particular kind of thing.

This term can be appropriated to describe how seasoned individuals might distinguish Rust from Go, or Ruby from Elixir at a glance.

Some just stick out like sore thumbs:

Perl, with all of its short variable names with special characters, reads like Q*bert swearing.

Lisp, whose profusion of parentheses is best captured by that old joke about the Russians in the 1980's proving that they had stolen the source code of some SDI missile interceptor code by showing the last page:

                )))
              ) )
            ))) ) ))
           ))))) 
          ))) 
        )) 
      )))) ))
    )))) ))
  )))
)

So if we were to go code-watching for the elusive Objective-C species, what would we look for? That's right:

  • Square brackets
  • Ridiculously-long method names
  • @'s

@, or "at" sign compiler directives, are as central to understanding Objective-C's gestalt as its ancestry and underlying mechanisms. It's the sugary glue that allows Objective-C to be such a powerful, expressive language, and yet still compile all the way down to C.

Its uses are varied and disparate, to the point that the only accurate way to describe what @ means by itself is "shorthand for something to do with Objective-C". They cover a broad range in usefulness and obscurity, from staples like @interface and @implementation to ones you could go your whole career without running into, like @defs and @compatibility_alias.

But to anyone aspiring to be an NSHipster, intimate familiarity with @ directives is tantamount to a music lover's ability to enumerate the entire Beatles catalog in chronological order (and most importantly, having unreasonably strong opinions about each of them).

Interface & Implementation

@interface and @implementation are the first things you learn about when you start Objective-C:

  • @interface...@end
  • @implementation...@end

What you don't learn about until later on, are categories and class extensions.

Categories allow you to extend the behavior of existing classes by adding new class or instance methods. As a convention, categories are defined in their own .{h,m} files, like so:

MyObject+CategoryName.h

@interfaceMyObject(CategoryName)-(void)foo;-(BOOL)barWithBaz:(NSInteger)baz;@end

MyObject+CategoryName.m

@implementationMyObject(CategoryName)-(void)foo{// ...}-(BOOL)barWithBaz:(NSInteger)baz{returnYES;}@end

Categories are particularly useful for convenience methods on standard framework classes (just don't go overboard with your utility functions).

Pro Tip: Rather than littering your code with random, arbitrary color values, create an NSColor / UIColor color palette category that defines class methods like +appNameDarkGrayColor. You can then add a semantic layer on top of that by creating method aliases like +appNameTextColor, which returns +appNameDarkGrayColor.

Extensions look like categories, but omit the category name. These are typically declared before an @implementation to specify a private interface, and even override properties declared in the interface:

@interfaceMyObject()@property(readwrite,nonatomic,strong)NSString*name;-(void)doSomething;@end@implementationMyObject@synthesizename=_name;// ...@end

Properties

Property directives are likewise concepts learned early on:

  • @property
  • @synthesize
  • @dynamic

One interesting note with properties is that as of Xcode 4.4, it is no longer necessary to explicitly synthesize properties. Properties declared in an @interface are automatically synthesized (with leading underscore ivar name, i.e. @synthesize propertyName = _propertyName) in the implementation.

Forward Class Declarations

Occasionally, @interface declarations will reference an external class in a property or as a parameter type. Rather than adding #import statements for each class, it's good practice to use forward class declarations in the header, and import them in the implementation.

  • @class

Shorter compile times, less chance of cyclical references; you should definitely get in the habit of doing this if you aren't already.

Instance Variable Visibility

It's a matter of general convention that classes provide state and mutating interfaces through properties and methods, rather than directly exposing ivars.

Although ARC makes working with ivars much safer by taking care of memory management, the aforementioned automatic property synthesis removes the one place where ivars would otherwise be declared.

Nonetheless, in cases where ivars are directly manipulated, there are the following visibility directives:

  • @public: instance variable can be read and written to directly, using the notation person->age = 32"
  • @package: instance variable is public, except outside of the framework in which it is specified (64-bit architectures only)
  • @protected: instance variable is only accessible to its class and derived classes
  • @private: instance variable is only accessible to its class
@interfacePerson : NSObject{@publicNSStringname;intage;@privateintsalary;}

Protocols

There's a distinct point early in an Objective-C programmer's evolution, when she realizes that she can define her own protocols.

The beauty of protocols is that they allow programmers to design contracts that can be adopted outside of a class hierarchy. It's the egalitarian mantra at the heart of the American Dream: that it doesn't matter who you are, or where you come from: anyone can achieve anything if they work hard enough.

...or at least that's idea, right?

  • @protocol...@end: Defines a set of methods to be implemented by any class conforming to the protocol, as if they were added to the interface of that class.

Architectural stability and expressiveness without the burden of coupling--protocols are awesome.

Requirement Options

You can further tailor a protocol by specifying methods as required or optional. Optional methods are stubbed in the interface, so as to be auto-completed in Xcode, but do not generate a warning if the method is not implemented. Protocol methods are required by default.

The syntax for @required and @optional follows that of the visibility macros:

@protocolCustomControlDelegate-(void)control:(CustomControl*)controldidSucceedWithResult:(id)result;@optional-(void)control:(CustomControl*)controldidFailWithError:(NSError*)error;@end

Exception Handling

Objective-C communicates unexpected state primarily through NSError. Whereas other languages would use exception handling for this, Objective-C relegates exceptions to truly exceptional behavior, including programmer error.

@ directives are used for the traditional convention of try/catch/finally blocks:

@try{// attempt to execute the following statements[selfgetValue:&valueerror:&error];// if an exception is raised, or explicitly thrown...if(error){@throwexception;}}@catch(NSException*e){// ...handle the exception here}@finally{// always execute this at the end of either the @try or @catch block[selfcleanup];}

Literals

Literals are shorthand notation for specifying fixed values. Literals are more -or-less directly correlated with programmer happiness. By this measure, Objective-C has long been a language of programmer misery.

Object Literals

Until recently, Objective-C only had literals for NSString. But with the release of the Apple LLVM 4.0 compiler, literals for NSNumber, NSArray and NSDictionary were added, with much rejoicing.

  • @"": Returns an NSString object initialized with the Unicode content inside the quotation marks.
  • @42, @3.14, @YES, @'Z': Returns an NSNumber object initialized with pertinent class constructor, such that @42[NSNumber numberWithInteger:42], or @YES[NSNumber numberWithBool:YES]. Supports the use of suffixes to further specify type, like @42U[NSNumber numberWithUnsignedInt:42U].
  • @[]: Returns an NSArray object initialized with the comma-delimited list of objects as its contents. For example, @[@"A", @NO, @2.718][NSArray arrayWithObjects:@"A", @NO, @2.718, nil] (note that sentinel nil is not required in literal).
  • @{}: Returns an NSDictionary object initialized with the specified key-value pairs as its contents, in the format: @{@"someKey" : @"theValue"}.
  • @(): Dynamically evaluates the boxed expression and returns the appropriate object literal based on its value (i.e. NSString for const char*, NSNumber for int, etc.). This is also the designated way to use number literals with enum values.

Objective-C Literals

Selectors and protocols can be passed as method parameters. @selector() and @protocol() serve as pseudo-literal directives that return a pointer to a particular selector (SEL) or protocol (Protocol *).

  • @selector(): Returns an SEL pointer to a selector with the specified name. Used in methods like -performSelector:withObject:.
  • @protocol(): Returns a Protocol * pointer to the protocol with the specified name. Used in methods like -conformsToProtocol:.

C Literals

Literals can also work the other way around, transforming Objective-C objects into C values. These directives in particular allow us to peek underneath the Objective-C veil, to begin to understand what's really going on.

Did you know that all Objective-C classes and objects are just glorified structs? Or that the entire identity of an object hinges on a single isa field in that struct?

For most of us, at least most of the time, coming into this knowledge is but an academic exercise. But for anyone venturing into low-level optimizations, this is simply the jumping-off point.

  • @encode(): Returns the type encoding of a type. This type value can be used as the first argument encode in NSCoder -encodeValueOfObjCType:at.
  • @defs(): Returns the layout of an Objective-C class. For example, to declare a struct with the same fields as an NSObject, you would simply do:
struct{@defs(NSObject)}

Ed. As pointed out by readers @secboffin& @ameaijou, @defs is unavailable in the modern Objective-C runtime.

Optimizations

There are some @ compiler directives specifically purposed for providing shortcuts for common optimizations.

  • @autoreleasepool{}: If your code contains a tight loop that creates lots of temporary objects, you can use the @autorelease directive to optimize for these short-lived, locally-scoped objects by being more aggressive about how they're deallocated. @autoreleasepool replaces and improves upon the old NSAutoreleasePool, which is significantly slower, and unavailable with ARC.
  • @synchronized(){}: This directive offers a convenient way to guarantee the safe execution of a particular block within a specified context (usually self). Locking in this way is expensive, however, so for classes aiming for a particular level of thread safety, a dedicated NSLock property or the use of low-level locking functions like OSAtomicCompareAndSwap32(3) are recommended.

Compatibility

In case all of the previous directives were old hat for you, there's a strong likelihood that you didn't know about this one:

  • @compatibility_alias: Allows existing classes to be aliased by a different name.

For example PSTCollectionView uses @compatibility_alias to significantly improve the experience of using the backwards-compatible, drop-in replacement for UICollectionView:

// Allows code to just use UICollectionView as if it would be available on iOS SDK 5.// http://developer.apple.    com/legacy/mac/library/#documentation/DeveloperTools/gcc-3.   3/gcc/compatibility_005falias.html#if __IPHONE_OS_VERSION_MAX_ALLOWED < 60000@compatibility_aliasUICollectionViewControllerPSTCollectionViewController;@compatibility_aliasUICollectionViewPSTCollectionView;@compatibility_aliasUICollectionReusableViewPSTCollectionReusableView;@compatibility_aliasUICollectionViewCellPSTCollectionViewCell;@compatibility_aliasUICollectionViewLayoutPSTCollectionViewLayout;@compatibility_aliasUICollectionViewFlowLayoutPSTCollectionViewFlowLayout;@compatibility_aliasUICollectionViewLayoutAttributesPSTCollectionViewLayoutAttributes;@protocolUICollectionViewDataSource<PSTCollectionViewDataSource>@end@protocolUICollectionViewDelegate<PSTCollectionViewDelegate>@end#endif

Using this clever combination of macros, a developer can develop with UICollectionView by including PSTCollectionView--without worrying about the deployment target of the final project. As a drop-in replacement, the same code works more-or-less identically on iOS 6 as it does on iOS 4.3.


So to review:

Interfaces & Implementation

  • @interface...@end
  • @implementation...@end
  • @class

Instance Variable Visibility

  • @public
  • @package
  • @protected
  • @private

Properties

  • @property
  • @synthesize
  • @dynamic

Protocols

  • @protocol
  • @required
  • @optional

Exception Handling

  • @try
  • @catch
  • @finally
  • @throw

Object Literals

  • @""
  • @42, @3.14, @YES, @'Z'
  • @[]
  • @{}
  • @()

Objective-C Literals

  • @selector()
  • @protocol()

C Literals

  • @encode()
  • @defs()

Optimizations

  • @autoreleasepool{}
  • @synchronized{}

Compatibility

  • @compatibility_alias

Thus concludes this exhaustive rundown of the many faces of @. It's a versatile, power-packed character, that embodies the underlying design and mechanisms of the language.

This should be a complete list, but there's always a chance that some new or long-forgotten ones slipped between the cracks. If you know of any @ directives that were left out, be sure to let @NSHipster know.

AddressBookUI

$
0
0

Address Book UI is an iOS framework for displaying, selecting, editing, and creating contacts in a user's Address Book. Similar to the Message UI framework, Address Book UI contains a number of controllers that can be presented modally, to provide common system functionality in a uniform interface.

To use the framework, add both AddressBook.framework and AddressBookUI.framework to your project, under the "Link Binary With Libraries" build phase.

At first glance, it would seem that there's nothing really remarkable about the Address Book UI framework.

Actually, in iOS 6, there are some fascinating inter-process shenanigans going on behind the scenes with modal controllers like MFMailComposeViewController and ABNewPersonViewController. Ole Begemann has an excellent write-up on Remote View Controllers in iOS 6 that's definitely worth a read.

However, tucked away from the rest of the controllers and protocols, there's a single Address Book UI function that's astoundingly useful:

ABCreateStringWithAddressDictionary() - Returns a localized, formatted address string from components.

The first argument for the function is a dictionary containing the address components, keyed by string constants:

  • kABPersonAddressStreetKey
  • kABPersonAddressCityKey
  • kABPersonAddressStateKey
  • kABPersonAddressZIPKey
  • kABPersonAddressCountryKey
  • kABPersonAddressCountryCodeKey

kABPersonAddressCountryCodeKey is an especially important attribute, as it determines which locale used to format the address string. If you are unsure of the country code, or one isn't provided with your particular data set, NSLocale may be able to help you out:

[mutableAddressComponentssetValue:[[[NSLocalealloc]initWithIdentifier:@"en_US"]objectForKey:NSLocaleCountryCode]forKey:(__bridgeNSString*)kABPersonAddressCountryCodeKey];

The second argument is a boolean flag, addCountryName. When YES, the name of the country corresponding to the specified country code will be automatically appended to the address. This should only used when the country code is known.

Nowhere else in all of the other frameworks is this functionality provided. It's not part of NSLocale, or even Map Kit or Core Location. For all of the care and attention to detail that Apple puts into localization, it's surprising that such an important task is relegated to the corners of an obscure, somewhat-unrelated framework.

Unfortunately, Address Book UI is not available in Mac OS X, and it would appear that there's no equivalent function provided on this platform.

For you see, address formats vary greatly across different regions. For example, addresses in the United States take the form:

Street Address
City State ZIP
Country

Whereas addresses in Japan follow a different convention:

Postal Code
Prefecture Municipality
Street Address
Country

This is at least as jarring a difference in localization as swapping periods for commas the radix point, so make sure to use this function anytime you're displaying an address from its components.

One great way to take advantage of localized address book formatting would be to check out FormatterKit, which added TTTAddressFormatter in its 1.1 release.

NSLinguisticTagger

$
0
0

NSLinguisticTagger is a veritable Swiss Army Knife of linguistic functionality, with the ability to tokenize natural language strings into words, determine their part-of-speech & stem, extract names of people, places, & organizations, and tell you the languages & respective writing system used in the string.

For most of us, this is far more power than we know what to do with. But perhaps this is just for lack sufficient opportunity to try. After all, almost every application deals with natural language in one way or another--perhaps NSLinguisticTagger could add a new level of polish, or enable brand new features entirely.


Introduced with iOS 5, NSLinguisticTagger is a contemporary to Siri, raising speculation that it was a byproduct of the personal assistant's development.

Consider a typical question we might ask Siri:

What is the weather in San Francisco?

Computers are a long ways off from "understanding" this question literally, but with a few simple tricks, we can do a reasonable job understanding the intention of the question:

NSString*question=@"What is the weather in San Francisco?";NSLinguisticTaggerOptionsoptions=NSLinguisticTaggerOmitWhitespace|NSLinguisticTaggerOmitPunctuation|NSLinguisticTaggerJoinNames;NSLinguisticTagger*tagger=[[NSLinguisticTaggeralloc]initWithTagSchemes:[NSLinguisticTaggeravailableTagSchemesForLanguage:@"en"]options:options];tagger.string=question;[taggerenumerateTagsInRange:NSMakeRange(0,[questionlength])scheme:NSLinguisticTagSchemeNameTypeOrLexicalClassoptions:optionsusingBlock:^(NSString*tag,NSRangetokenRange,NSRangesentenceRange,BOOL*stop){NSString*token=[questionsubstringWithRange:tokenRange];NSLog(@"%@: %@",token,tag);}];

This code would print the following:

What: Pronoun
is: Verb
the: Determiner
weather: Noun
in: Preposition
San Francisco: PlaceName

If we filter on nouns, verbs, and place name, we get [is, weather, San Francisco].

Just based on this alone, or perhaps in conjunction with something like the Latent Semantic Mapping framework, we can conclude that a reasonable course of action would be to make an API request to determine the current weather conditions in San Francisco.

Tagging Schemes

NSLinguisticTagger can be configured to tag different kinds of information by specifying any of the following tagging schemes:

  • NSLinguisticTagSchemeTokenType: Classifies tokens according to their broad type: word, punctuation, whitespace, etc.
  • NSLinguisticTagSchemeLexicalClass: Classifies tokens according to class: part of speech for words, type of punctuation or whitespace, etc.
  • NSLinguisticTagSchemeNameType: Classifies tokens as to whether they are part of named entities of various types or not.
  • NSLinguisticTagSchemeNameTypeOrLexicalClass: Follows NSLinguisticTagSchemeNameType for names, and NSLinguisticTagSchemeLexicalClass for all other tokens.

Here's a list of the various token types associated with each scheme (NSLinguisticTagSchemeNameTypeOrLexicalClass, as the name implies, is the union between NSLinguisticTagSchemeNameType& NSLinguisticTagSchemeLexicalClass):

NSLinguisticTagSchemeTokenTypeNSLinguisticTagSchemeLexicalClassNSLinguisticTagSchemeNameType
  • NSLinguisticTagWord
  • NSLinguisticTagPunctuation
  • NSLinguisticTagWhitespace
  • NSLinguisticTagOther
  • NSLinguisticTagNoun
  • NSLinguisticTagVerb
  • NSLinguisticTagAdjective
  • NSLinguisticTagAdverb
  • NSLinguisticTagPronoun
  • NSLinguisticTagDeterminer
  • NSLinguisticTagParticle
  • NSLinguisticTagPreposition
  • NSLinguisticTagNumber
  • NSLinguisticTagConjunction
  • NSLinguisticTagInterjection
  • NSLinguisticTagClassifier
  • NSLinguisticTagIdiom
  • NSLinguisticTagOtherWord
  • NSLinguisticTagSentenceTerminator
  • NSLinguisticTagOpenQuote
  • NSLinguisticTagCloseQuote
  • NSLinguisticTagOpenParenthesis
  • NSLinguisticTagCloseParenthesis
  • NSLinguisticTagWordJoiner
  • NSLinguisticTagDash
  • NSLinguisticTagOtherPunctuation
  • NSLinguisticTagParagraphBreak
  • NSLinguisticTagOtherWhitespace
  • NSLinguisticTagPersonalName
  • NSLinguisticTagPlaceName
  • NSLinguisticTagOrganizationName

So for basic tokenization, use NSLinguisticTagSchemeTokenType, which will allow you to distinguish between words and whitespace or punctuation. For information like part-of-speech, or differentiation between different parts of speech, NSLinguisticTagSchemeLexicalClass is your new bicycle.

Continuing with the tagging schemes:

  • NSLinguisticTagSchemeLemma: This tag scheme supplies a stem forms of the words, if known.
  • NSLinguisticTagSchemeLanguage: Tags tokens according to their script. The tag values will be standard language abbreviations such as "en", "fr", "de", etc., as used with the NSOrthography class. Note that the tagger generally attempts to determine the language of text at the level of an entire sentence or paragraph, rather than word by word.
  • NSLinguisticTagSchemeScript: Tags tokens according to their script. The tag values will be standard script abbreviations such as "Latn", "Cyrl", "Jpan", "Hans", "Hant", etc.

As demonstrated in the example above, first you initialize an NSLinguisticTagger with an array of all of the different schemes that you wish to use, and then assign or enumerate each of the tags after specifying the tagger's input string.

Tagging Options

In addition to the available tagging schemes, there are several options you can pass to NSLinguisticTagger (combined with bitwise OR |) to slightly change its behavior:

  • NSLinguisticTaggerOmitWords
  • NSLinguisticTaggerOmitPunctuation
  • NSLinguisticTaggerOmitWhitespace
  • NSLinguisticTaggerOmitOther

Each of these options omit the broad categories of tags described. For example, NSLinguisticTagSchemeLexicalClass, which distinguishes between many different kinds of punctuation, all of those would be omitted with NSLinguisticTaggerOmitPunctuation. This is preferable to manually filtering these tag types in enumeration blocks or with predicates.

The last option is specific to NSLinguisticTagSchemeNameType:

  • NSLinguisticTaggerJoinNames

By default, each token in a name is treated as separate instances. In many circumstances, it makes sense to treat names like "San Francisco" as a single token, rather than two separate tokens. Passing this token makes this so.


Natural language is woefully under-utilized in user interface design on mobile devices. When implemented effectively, a single utterance from the user can achieve the equivalent of a handful of touch interactions, in a fraction of the time.

Sure, it's not easy, but if we spent a fraction of the time we use to make our visual interfaces pixel-perfect, we could completely re-imagine how users best interact with apps and devices. And with NSLinguisticTagger, it's never been easier to get started.


UILocalizedIndexedCollation

$
0
0

UITableView starts to become unwieldy once it gets to a few hundred rows. If users are reduced to frantically scratching at the screen like a cat playing Fruit Ninja in order to get at what they want... you may want to rethink your UI approach.

So, what are your options?

Well, you could organize your data into a hierarchy, which could dramatically reduce the number of rows displayed on each screen in fashion, based on its branching factor.

You could also add a UISearchBar to the top of your table view, allowing the user to filter on keywords to get exactly what they're looking for (or--perhaps more importantly--determine that what they seek doesn't exist in the first place).

There is also a third approach, which is generally under-utilized in iOS applications: section index titles. These are the vertically flowing letters found along the right side of table views in your Address Book contacts list or Music library:

Section Index Titles Example

As the user scrolls their finger down the list, the table view jumps to the corresponding section. Even the most tiresome table view is rendered significantly more usable as a result.

Section index titles can be enabled by implementing the following UITableViewDataSource delegate methods:

  • -sectionIndexTitlesForTableView: - Returns an array of the section index titles to be displayed along the right hand side of the table view, such as the alphabetical list "A...Z" + "#". Section index titles are short--generally limited to 2 Unicode characters.

  • -tableView:sectionForSectionIndexTitle:atIndex: - Returns the section index that the table view should jump to when the user touches a particular section index title.

As longtime readers of NSHipster doubtless have already guessed, the process of generating that alphabetical list is not something you would want to have to generate yourself. What it means to something to be alphabetically sorted, or even what is meant by an "alphabet" varies wildly across different locales.

Coming to our rescue is UILocalizedIndexedCollation.


UILocalizedIndexedCollation is a class that helps to organize data in table views with section index titles in a locale-aware manner. Rather than creating the object directly, a shared instance corresponding to the current locale supported by your application is accessed, with UILocalizedIndexedCollation +currentCollation

The first task for UILocalizedIndexedCollation is to determine what section index titles to display for the current locale, which are can be read from the sectionIndexTitles property.

To give you a better idea of how section index titles vary between locales:

In order to see these for yourself, you'll need to explicitly add the desired locales to your Project Localizations list.

LocaleSection Index Titles
en_USA, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, #
ja_JPA, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, あ, か, さ, た, な, は, ま, や, ら, わ, #
sv_SEA, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, Å, Ä, Ö, #
ko_KOA, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, ㄱ, ㄴ, ㄷ, ㄹ, ㅁ, ㅂ, ㅅ, ㅇ, ㅈ, ㅊ, ㅋ, ㅌ, ㅍ, ㅎ, #
ar_SAA, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, آ, ب, ت, ث, ج, ح, خ, د, ذ, ر, ز, س, ش, ص, ض, ط, ظ, ع, غ, ف, ق, ك, ل, م, ن, ه, و, ي, #

Aren't you glad you don't have to do this yourself?

So with the list of section titles laid out before you, the next step is to determine what section each object should be assigned to. This is accomplished with -sectionForObject:collationStringSelector:. This method returns the NSInteger index corresponding to the string value of the object when performing the specified selector. This selector might be something like localizedName, title, or even just description.

So, as it stands, your table view data source has a NSArray property corresponding to the number of sections in the table view, with each element of the array containing an array representing each row in the section. Since collation was handled by UILocalizedIndexedCollation, it makes sense for it to sort the rows in each section as well. – sortedArrayFromArray:collationStringSelector: does this in similar fashion to -sectionForObject:collationStringSelector:, by sorting the objects in the section by their respective localized title.

Finally, the table view should implement -tableView:sectionForSectionIndexTitle:atIndex:, so that touching a section index title jumps to the corresponding section in the table view. UILocalizedIndexedCollation -sectionForSectionIndexTitleAtIndex: does the trick.

All told, here's what a typical table view data source implementation looks like:

-(void)setObjects:(NSArray*)objects{SELselector=@selector(localizedTitle)NSIntegerindex,sectionTitlesCount=[[[UILocalizedIndexedCollationcurrentCollation]sectionTitles]count];NSMutableArray*mutableSections=[[NSMutableArrayalloc]initWithCapacity:sectionTitlesCount];for(idx=0;idx<sectionTitlesCount;idx++){[mutableSectionsaddObject:[NSArrayarray]];}for(idobjectinobjects){NSIntegersectionNumber=[[UILocalizedIndexedCollationcurrentCollation]sectionForObject:objectcollationStringSelector:selector];[[mutableSectionsobjectAtIndex:sectionNumber]addObject:object];}for(idx=0;idx<sectionTitlesCount;idx++){NSArray*objectsForSection=[mutableSectionsobjectAtIndex:idx];[mutableSectionsreplaceObjectAtIndex:idxwithObject:[collationsortedArrayFromArray:objectsForSectioncollationStringSelector:selector]];}self.sections=mutableSections;[self.tableViewreloadData];}-(NSString*)tableView:(UITableView*)tableViewtitleForHeaderInSection:(NSInteger)section{return[[[UILocalizedIndexedCollationcurrentCollation]sectionTitles]objectAtIndex:section];}-(NSArray*)sectionIndexTitlesForTableView:(UITableView*)tableView{return[[UILocalizedIndexedCollationcurrentCollation]sectionIndexTitles];}-(NSInteger)tableView:(UITableView*)tableViewsectionForSectionIndexTitle:(NSString*)titleatIndex:(NSInteger)index{return[[UILocalizedIndexedCollationcurrentCollation]sectionForSectionIndexTitleAtIndex:index];}

UITableViewIndexSearch

There is one special section index title worth mentioning, and that's UITableViewIndexSearch. It's a common pattern to have both a search bar and section indexes. In equal parts convenience and visual consistency, a search icon is often included as the first section index title, which can be touched to bring up the UISearchBar in the header of the table view.

To include the search icon in your table view, you would simply prepend the NSString constant UITableViewIndexSearch to the return value of -sectionIndexTitlesForTableView:, and adjust -tableView:sectionForSectionIndexTitle:atIndex: to account for the single element shift.


So remember, NSHipsters one and all: if you see an excessively long table view, kill it with fire!

...which is to say, refactor your content with some combination of hierarchies, a search bar, and section indexes. And when implementing section index titles, take advantage of UILocalizedIndexedCollation.

Together, we can put an end to scroll view-induced repetitive stress injuries, and spend more time enjoying the finer things in life, like watching videos of pets playing with iPads.

NSURLProtocol

$
0
0

iOS is all about networking--whether it's reading or writing state to and from the server, offloading computation to a distributed system, or loading remote images, audio, and video from the cloud.

Because of this, Foundation's URL Loading System is something that every iOS developer would do well to buddy up with.

When given the choice, applications should adopt the highest-level framework possible for what needs to be done. So, if that task is communicating over http://, https:// or ftp://, then NSURLConnection and friends are a clear choice. Apple's networking classes cover the essentials for modern Objective-C application development, from URL and cache management to authentication & cookie storage:

The URL Loading System
URL Loading
NSURLConnection
NSURLRequestNSMutableURLRequest
NSURLResponseNSHTTPURLResponse
Cache Management
NSURLCache
NSCacheURLRequest
NSCachedURLResponse
Authentication & Credentials
NSURLCredential
NSURLCredentialStorage
NSURLAuthenticationChallenge
NSURLProtectionSpace
Cookie Storage
NSHTTPCookie
NSHTTPCookieStorage
Protocol Support
NSURLProtocol

Although there's a lot to the URL Loading System, it's designed in a way that hides the underlying complexity, with hooks to provide configuration when needed. Any request going through NSURLConnection is intercepted by other parts of the system along the way, allowing for things like cached responses being transparently loaded from disk when available.

Which brings us to this week's topic: NSURLProtocol.


NSURLProtocol is both the most obscure and the most powerful part of the URL Loading System. It's an abstract class that allows subclasses to define the URL loading behavior of new or existing schemes.

If you aren't already mindblown.gif, here are some examples of what this can be used for, without changing anything else about how requests are loaded:

Again, it's important to reiterate that the whole point of NSURLProtocol is that you can change everything about the loading behavior of your application without doing anything differently with how your application communicates to the network.

Or, put another way: NSURLProtocol is an Apple-sanctioned man-in-the-middle attack.

Subclassing NSURLProtocol

As mentioned previously, NSURLProtocol is an abstract class, which means it will be subclassed rather than used directly.

Determining if a Subclass Can Handle a Request

The first task of an NSURLProtocol subclass is to define what requests to handle. For example, if you want to serve bundle resources when available, it would only want to respond to requests that matched the name of an existing resource.

This logic is specified in +canInitWithRequest:. If YES, the specified request is handled. If NO, it's passed down the line to the next URL Protocol.

Providing a Canonical Version of a Request

If you wanted to modify a request in any particular way, +canonicalRequestForRequest: is your opportunity. It's up to each subclass to determine what "canonical" means, but the gist is that a protocol should ensure that a request has only one canonical form (although many different requests may normalize into the same canonical form).

Getting and Setting Properties on Requests

NSURLProtocol provides methods that allow you to add, retrieve, and remove arbitrary metadata to a request object--without the need for a private category or swizzling:

  • +propertyForKey:inRequest:
  • +setProperty:forKey:inRequest:
  • +removePropertyForKey:inRequest:

This is especially important for subclasses created to interact with protocols that have information not already provided by NSURLRequest. It can also be useful as a way to pass state between other methods in your implementation.

Loading Requests

The most important methods in your subclass are -startLoading and -stopLoading. What goes into either of these methods is entirely dependent on what your subclass is trying to accomplish, but there is one commonality: communicating with the protocol client.

Each instance of a NSURLProtocol subclass has a client property, which is the object that is communicating with the URL Loading system. It's not NSURLConnection, but the object does conform to a protocol that should look familiar to anyone who has implemented NSURLConnectionDelegate

<NSURLProtocolClient>

  • -URLProtocol:cachedResponseIsValid:
  • -URLProtocol:didCancelAuthenticationChallenge:
  • -URLProtocol:didFailWithError:
  • -URLProtocol:didLoadData:
  • -URLProtocol:didReceiveAuthenticationChallenge:
  • -URLProtocol:didReceiveResponse:cacheStoragePolicy:
  • -URLProtocol:wasRedirectedToRequest:redirectResponse:
  • -URLProtocolDidFinishLoading:

In your implementation of -startLoading and -stopLoading, you will need to send each delegate method to your client when appropriate. For something simple, this may mean sending several in rapid succession, but it's important nonetheless.

Registering the Subclass with the URL Loading System

Finally, in order to actually use an NSURLProtocol subclass, it needs to be registered into the URL Loading System.

When a request is loaded, each registered protocol is asked "hey, can you handle this request?". The first one to respond with YES with +canInitWithRequest: gets to handle the request. URL protocols are consulted in reverse order of when they were registered, so by calling [NSURLProtocol registerClass:[MyURLProtocol class]]; in -application:didFinishLoadingWithOptions:, your protocol will have priority over any of the built-in protocols.


Like the URL Loading System that contains it, NSURLProtocol is incredibly powerful, and can be used in exceedingly clever ways. As a relatively obscure class, we've only just started to mine its potential for how we can use it to make our code cleaner, faster, and more robust.

So go forth and hack! I can't wait to see what y'all come up with!

NSValueTransformer

$
0
0

Of all the Foundation classes, NSValueTransformer is perhaps the one that fared the worst in the shift from OS X to iOS.

Why? Well, there are two reasons:

The first and most obvious reason is that NSValueTransformer was mainly used in AppKit with Cocoa bindings. Here, they could automatically transform values from one property to another without the need of intermediary glue code, like for negating a boolean, or checking whether a value was nil. iOS, of course, doesn't have bindings.

The second reason has less to do with iOS than the Objective-C runtime itself. With the introduction of blocks, it got a whole lot easier to pass behavior between objects--significantly easier than, say NSValueTransformer or NSInvocation. So even if iOS were to get bindings tomorrow, it's uncertain as to whether NSValueTransformer would play as significant a role this time around.

But you know what? NSValueTransformer is ripe for a comeback. With a little bit of re-tooling and some recontextualization, this blast from the past could be the next big thing in your application.


NSValueTransformer is an abstract class that transforms one value into another. A transformation specifies what kinds of input values can be handled, and can even supports reversible transformations, where applicable.

A typical implementation would look something like this:

@interfaceClassNameTransformer: NSValueTransformer{}@end#pragma mark -@implementationClassNameTransformer+(Class)transformedValueClass{return[NSStringclass];}+(BOOL)allowsReverseTransformation{returnNO;}-(id)transformedValue:(id)value{return(value==nil)?nil:NSStringFromClass([valueclass]);}@end

NSValueTransformer is rarely initialized directly. Instead, it follows a pattern familiar to fans of NSPersistentStore or NSURLProtocol, where a class is registered, and instances are created from a manager--except in this case, you register the instance to act as a singleton (with a particular name):

NSString*constClassNameTransformerName=@"ClassNameTransformer";// Set the value transformer[NSValueTransformersetValueTransformer:[[ClassNameTransformeralloc]init]forName:ClassNameTransformerName];// Get the value transformerNSValueTransformer*valueTransformer=[NSValueTransformervalueTransformerForName:ClassNameTransformerName];

Typically, the singleton instance would be registered in the +initialize method of the value transformer subclass, so it could be used without further setup.

Now, at this point, you probably realize NSValueTransformer's fatal flaw: it's a pain in the ass to set up! Create a class, implement a handful of simple methods, define a constant, and register it in an +initialize method? No thanks.

In this age of blocks, we want--nay, demand--a way to declare functionality in one (albeit gigantic) line of code.

Nothing a little metaprogramming can't fix. Behold:

NSString*constTKCapitalizedStringTransformerName=@"TKCapitalizedStringTransformerName";[NSValueTransformerregisterValueTransformerWithName:TKCapitalizedStringTransformerNametransformedValueClass:[NSStringclass]returningTransformedValueWithBlock:^id(idvalue){return[valuecapitalizedString];}];

Not to break the 4th wall or anything, but in the middle of writing this article, I was compelled to see what could be done to improve the experience of NSValueTransformer. What I came up with was TransformerKit.

The entire library is based on some objc runtime hackery in an NSValueTransformer category. Also included with this category are a number of convenient examples, like string case transformers (i.e. CamelCase, llamaCase, snake_case, and train-case).

Now with its sexy new getup, we start to form a better understanding of where this could be useful:

  • NSValueTransformers are the ideal way to represent an ordered chain of fixed transformations. For instance, an app interfacing with a legacy system might transform user input through a succession of string transformations (trim whitespace, remove diacritics, and then capitalize letters) before sending it off to the mainframe.
  • Unlike blocks, NSValueTransformer encapsulates reversible transformations. Let's say you were wanted to map keys from a REST API representation into a Model object; you could create a reversible transformation that converted snake_case to llamaCase when initializing, and llamaCase to snake_case when serializing back to the server.
  • Another advantage over blocks is that NSValueTransformer subclasses can expose new properties that could be used to configure behavior in a particular way. Access to ivars also make it easier to cleanly memoize results, or do any necessary book-keeping along the way.
  • Lest we forget, NSValueTransformer can be used with Core Data, as a way to encode and decode compound data types from blob fields. It seems to have fallen out of fashion over the years, but serializing simple collections in this way, for example, is an excellent strategy for information that isn't well-modeled as its own entity. Just don't serialize images to a database this way--that's generally a Bad Idea™.

And the list goes on.


NSValueTransformer, far from a vestige of AppKit, remains Foundation's purest connection to that fundamental concept of computation: input goes in, output comes out.

Although it hasn't aged very well on its own, a little modernization restores NSValueTransformer to that highest esteem of NSHipsterdom: the solution that we didn't know we needed, but was there all along.

NS_ENUM & NS_OPTIONS

$
0
0

When everything is an object, nothing is.

So, there are a few ways you could parse that, but for the purposes of this article, this is all to say: sometimes it's nice to be able to drop down to the C layer of things.

Yes--that non-objective part of our favorite Smalltalk-inspired hybrid language, C can be a great asset. It's fast, it's battle-tested, it's the very foundation of modern computing. But more than that, C is the escape hatch for when the Object-Oriented paradigm cracks under its own cognitive weight.

Static functions are nicer than shoe-horned class methods.
Enums are nicer than string constants.
Bitmasks are nicer than arrays of string constants.
Preprocessor directives are nicer than runtime hacks.

A skilled Objective-C developer is able to gracefully switch between Objective and Procedural paradigms, and use each to their own advantage.

And on that note, this week's topic has to do with two simple-but-handy macros: NS_ENUM and NS_OPTIONS.


Introduced in Foundation with iOS 6 / Mac OS X 10.8, the NS_ENUM and NS_OPTIONS macros are the new, preferred way to declare enum types.

If you'd like to use either macro when targeting a previous version of iOS or OS X, you can simply inline like so:

#ifndef NS_ENUM#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type#endif

enum, or enumerated value types, are the C way to define constants for fixed values, like days of the week, or available styles of table view cells. In an enum declaration, constants without explicit values will automatically be assigned values sequentially, starting from 0.

There are several legal ways that enums can be defined. What's confusing is that there are subtle functional differences between each approach, and without knowing any better, someone is just as likely to use them interchangeably.

For instance:

enum{UITableViewCellStyleDefault,UITableViewCellStyleValue1,UITableViewCellStyleValue2,UITableViewCellStyleSubtitle};

...declares integer values, but no type.

Whereas:

typedefenum{UITableViewCellStyleDefault,UITableViewCellStyleValue1,UITableViewCellStyleValue2,UITableViewCellStyleSubtitle}UITableViewCellStyle;

...defines the UITableViewCellStyle type, suitable for specifying the type of method parameters.

However, Apple had previously defined all of their enum types as:

typedefenum{UITableViewCellStyleDefault,UITableViewCellStyleValue1,UITableViewCellStyleValue2,UITableViewCellStyleSubtitle};typedefNSIntegerUITableViewCellStyle;

...which ensures a fixed size for UITableViewCellStyle, but does nothing to hint the relation between the aforementioned enum and the new type to the compiler.

Thankfully, Apple has decided on "One Macro To Rule Them All" with NS_ENUM.

NS_ENUM

Now, UITableViewCellStyle is declared with:

typedefNS_ENUM(NSInteger,UITableViewCellStyle){UITableViewCellStyleDefault,UITableViewCellStyleValue1,UITableViewCellStyleValue2,UITableViewCellStyleSubtitle};

The first argument for NS_ENUM is the type used to store the new type. In a 64-bit environment, UITableViewCellStyle will be 8 bytes long--same as NSInteger. Make sure that the specified size can fit all of the defined values, or else an error will be generated. The second argument is the name of the new type (as you probably guessed). Inside the block, the values are defined as usual.

This approach combines the best of all of the aforementioned approaches, and even provides hints to the compiler for type-checking and switch statement completeness.

NS_OPTIONS

enum can also be used to define a bitmask. Using a convenient property of binary math, a single integer value can encode a combination of values all at once using the bitwise OR (|), and decoded with bitwise AND (&). Each subsequent value, rather than automatically being incremented by 1 from 0, are manually given a value with a bit offset: 1 << 0, 1 << 1, 1 << 2, and so on. If you imagine the binary representation of a number, like 10110 for 22, each bit can be though to represent a single boolean. In UIKit, for example, UIViewAutoresizing is a bitmask that can represent any combination of flexible top, bottom, left, and right margins, or width and height.

Rather than NS_ENUM, bitmasks should now use the NS_OPTIONS macro.

The syntax is exactly the same as NS_ENUM, but this macro alerts the compiler to how values can be combined with bitmask |. Again, you must be careful that all of the enumerated values fit within the specified type.


NS_ENUM and NS_OPTIONS are handy additions to the Objective-C development experience, and reaffirm the healthy dialectic between its objective and procedural nature. Keep this in mind as you move forward in your own journey to understand the logical tensions that underpin everything around us.

NSOrderedSet

$
0
0

Here's a question: why isn't NSOrderedSet a subclass of NSSet?

It seems perfectly logical, after all, for NSOrderedSet--a class that enforces the same uniqueness constraint of NSSet--to be a subclass of NSSet. It has the same methods as NSSet, with the addition of some NSArray-style methods like objectAtIndex:. By all accounts, it would seem to perfectly satisfy the requirements of the Liskov substitution principle, that:

If S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program.

So why is NSOrderedSet a subclass of NSObject and not NSSet or even NSArray?

Mutable / Immutable Class Clusters

Class Clusters are a design pattern at the heart of the Foundation framework; the essence of Objective-C's simplicity in everyday use.

But class clusters offer simplicity at the expense of extensibility, which becomes especially tricky when it comes to mutable / immutable class pairs like NSSet / NSMutableSet.

As expertly demonstrated by Tom Dalling in this Stack Overflow question, the method -mutableCopy creates an inconsistency that is inherent to Objective-C's constraint on single inheritance.

To start, let's look at how -mutableCopy is supposed to work in a class cluster:

NSSet*immutable=[NSSetset];NSMutableSet*mutable=[immutablemutableCopy];[mutableisKindOfClass:[NSSetclass]];// YES[mutableisKindOfClass:[NSMutableSetclass]];// YES

Now let's suppose that NSOrderedSet was indeed a subclass of NSSet:

// @interface NSOrderedSet : NSSetNSOrderedSet*immutable=[NSOrderedSetorderedSet];NSMutableOrderedSet*mutable=[immutablemutableCopy];[mutableisKindOfClass:[NSSetclass]];// YES[mutableisKindOfClass:[NSMutableSetclass]];// NO (!)

That's no good... since NSMutableOrderedSet couldn't be used as a method parameter of type NSMutableSet. So what happens if we make NSMutableOrderedSet a subclass of NSMutableSet as well?

// @interface NSOrderedSet : NSSet// @interface NSMutableOrderedSet : NSMutableSetNSOrderedSet*immutable=[NSOrderedSetorderedSet];NSMutableOrderedSet*mutable=[immutablemutableCopy];[mutableisKindOfClass:[NSSetclass]];// YES[mutableisKindOfClass:[NSMutableSetclass]];// YES[mutableisKindOfClass:[NSOrderedSetclass]];// NO (!)

This is perhaps even worse, as now NSMutableOrderedSet couldn't be used as a method parameter expecting an NSOrderedSet.

No matter how we approach it, we can't stack a mutable / immutable class pair on top of another existing mutable / immutable class pair. It just won't work in Objective-C.

Rather than subject ourselves to the perils of multiple inheritance, we could use Protocols to get us out of this pickle (as it does every other time the spectre of multiple inheritance is raised). Indeed, Foundation's collection classes could become more aspect-oriented by adding protocols:

  • NSArray : NSObject <NSOrderedCollection>
  • NSSet : NSObject <NSUniqueCollection>
  • NSOrderedSet : NSObject <NSOrderedCollection, NSUniqueCollection>

However, to reap any benefit from this arrangement, all of the existing APIs would have to be restructured to have parameters accept id <NSOrderedCollection> instead of NSArray. But the transition would be painful, and would likely open up a whole can of edge cases... which would mean that it would never be fully adopted... which would mean that there's less incentive to adopt this approach when defining your own APIs... which are less fun to write because there's now two incompatible ways to do something instead of one... which...

...wait, why would we use NSOrderedSet in the first place, anyway?


NSOrderedSet was introduced in iOS 5 & Mac OS X 10.7. The only APIs changed to add support for NSOrderedSet, though, were part of Core Data.

This was fantastic news for anyone using Core Data at the time, as it solved one of the long-standing annoyances of not having a way to arbitrarily order relationship collections. Previously, you'd have to add a position attribute, which would be re-calculated every time a collection was modified. There wasn't a built-in way to validate that your collection positions were unique or that the sequence didn't have any gaps.

In this way, NSOrderedSet is an answer to our prayers.

Unfortunately, its very existence in Foundation has created something between an attractive nuisance and a red herring for API designers.

Although it is perfectly suited to that one particular use case in Core Data, NSOrderedSet is probably not a great choice for the majority of APIs that could potentially use it. In cases where a simple collection of objects is passed as a parameter, a simple NSArray does the trick--even if there is an implicit understanding that you shouldn't have duplicate entries. This is even more the case when order matters for a collection parameter--just use NSArray (there should be code to deal with duplicates in the implementation anyway). If uniqueness does matter, or the semantics of sets makes sense for a particular method, NSSet has and remains a great choice.


So, as a general rule: NSOrderedSet is useful for intermediary and internal representations, but you probably shouldn't introduce it as a method parameters unless it's particularly well-suited to the semantics of the data model.

If nothing else, NSOrderedSet illuminates some of the fascinating implications of Foundation's use of the class cluster design pattern. In doing so, it allows us better understand the trade-off between simplicity and extensibility as we make these choices in our own application designs.

KVC Collection Operators

$
0
0

Rubyists laugh at Objective-C's bloated syntax.

Although we lost a few pounds over the summer with our sleek new object literals, those Red-headed bullies still taunt us with their map one-liners and their fancy Symbol#to_proc.

Really, a lot of how elegant (or clever) a language is comes down to how well it avoids loops. for, while; even fast enumeration expressions are a drag. No matter how you sugar-coat them, loops will be a block of code that does something that is much simpler to describe in natural language.

"get me the average salary of all of the employees in this array", versus...

doubletotalSalary=0.0;for(Employee*employeeinemployees){totalSalary+=[employee.salarydoubleValue];}doubleaverageSalary=totalSalary/[employeescount];

Meh.

Fortunately, Key-Value Coding gives us a much more concise--almost Ruby-like--way to do this:

[employeesvalueForKeyPath:@"@avg.salary"];

KVC Collection Operators allows actions to be performed on a collection using key path notation in valueForKeyPath:. Any time you see @ in a key path, it denotes a particular aggregate function whose result can be returned or chained, just like any other key path.

Collection Operators fall into one of three different categories, according to the kind of value they return:

  • Simple Collection Operators return strings, numbers, or dates, depending on the operator.
  • Object Operators return an array.
  • Array and Set Operators return an array or set, depending on the operator.

The best way to understand how these work is to see them in action. Consider a Product class, and a products array with the following data:

@interfaceProduct : NSObject@propertyNSString*name;@propertydoubleprice;@propertyNSDate*launchedOn;@end

Key-Value Coding automatically boxes and un-boxes scalars into NSNumber or NSValue as necessary to make everything work.

NamePriceLaunch Date
iPhone 5$199September 21, 2012
iPad Mini$329November 2, 2012
MacBook Pro$1699June 11, 2012
iMac$1299November 2, 2012

Simple Collection Operators

  • @count: Returns the number of objects in the collection as an NSNumber.
  • @sum: Converts each object in the collection to a double, computes the sum, and returns the sum as an NSNumber.
  • @avg: Takes the double value of each object in the collection, and returns the average value as an NSNumber.
  • @max: Determines the maximum value using compare:. Objects must support comparison with one another for this to work.
  • @min: Same as @max, but returns the minimum value in the collection.

Example:

[productsvalueForKeyPath:@"@count"];// 4[productsvalueForKeyPath:@"@sum.price"];// 3526.00[productsvalueForKeyPath:@"@avg.price"];// 881.50[productsvalueForKeyPath:@"@max.price"];// 1699.00[productsvalueForKeyPath:@"@min.launchedOn"];// June 11, 2012

Pro Tip: To get the aggregate value of an array or set of NSNumbers, you can simply pass self as the key path after the operator, e.g. [@[@(1), @(2), @(3)] valueForKeyPath:@"@max.self"] (/via @davandermobile, citing Objective Sea)

Object Operators

Let's say we have an inventory array, representing the current stock of our local Apple store (which is running low on iPad Mini, and doesn't have the new iMac, which hasn't shipped yet):

NSArray*inventory=@[iPhone5,iPhone5,iPhone5,iPadMini,macBookPro,macBookPro];
  • @unionOfObjects / @distinctUnionOfObjects: Returns an array of the objects in the property specified in the key path to the right of the operator. @distinctUnionOfObjects removes duplicates, whereas @unionOfObjects does not.

Example:

[inventoryvalueForKeyPath:@"@unionOfObjects.name"];// "iPhone 5", "iPhone 5", "iPhone 5", "iPad Mini", "MacBook Pro", "MacBook Pro"[inventoryvalueForKeyPath:@"@distinctUnionOfObjects.name"];// "iPhone 5", "iPad Mini", "MacBook Pro"

Array and Set Operators

Array and Set Operators are similar to Object Operators, but they work on collections of NSArray and NSSet.

This would be useful if we were to, for example, compare the inventory of several stores, say appleStoreInventory, (same as in the previous example) and verizonStoreInventory (which sells iPhone 5 and iPad Mini, and has both in stock).

  • @distinctUnionOfArrays / @unionOfArrays: Returns an array containing the combined values of each array in the collection, as specified by the key path to the right of the operator. As you'd expect, the distinct version removes duplicate values.
  • @distinctUnionOfSets: Similar to @distinctUnionOfArrays, but it expects an NSSet containing NSSet objects, and returns an NSSet. Because sets can't contain duplicate values anyway, there is only the distinct operator.

Example:

[@[appleStoreInventory,verizonStoreInventory]valueForKeyPath:@"@distinctUnionOfArrays.name"];// "iPhone 5", "iPad Mini", "MacBook Pro"  

This is Probably a Terrible Idea

Curiously, Apple's documentation on KVC collection operators goes out of its way to make the following point:

Note: It is not currently possible to define your own collection operators.

This makes sense to spell out, since that's what most people are thinking about once they see collection operators for the first time.

However, as it turns out, it is actually possible, with a little help from our friend, objc/runtime.

Guy English has a pretty amazing post wherein he swizzles valueForKeyPath: to parse a custom-defined DSL, which extends the existing offerings to interesting effect:

NSArray*names=[allEmployeesvalueForKeyPath:@"[collect].{daysOff<10}.name"];

This code would get the names of anyone who has taken fewer than 10 days off (to remind them to take a vacation, no doubt!).

Or, taken to a ridiculous extreme:

NSArray*albumCovers=[recordsvalueForKeyPath:@"[collect].{artist like 'Bon Iver'}.<NSUnarchiveFromDataTransformerName>.albumCoverImageData"];

Eat your heart out, Ruby. This one-liner filters a record collection for artists whose name matches "Bon Iver", and initializes an NSImage from the album cover image data of the matching albums.

Is this a good idea? Probably not. (NSPredicate is rad, and breaking complicated logic up is under-rated)

Is this insanely cool? You bet! This clever example has shown a possible direction for future Objective-C DSLs and meta-programming.


KVC Collection Operators are a must-know for anyone who wants to save a few extra lines of code and look cool in the process.

While scripting languages like Ruby boast considerably more flexibility in its one-liner capability, perhaps we should take a moment to celebrate the restraint built into Objective-C and Collection Operators. After all, Ruby is hella slow, amiright? </troll>

instancetype

$
0
0

Want to know what's coming next in Objective-C? Keep your ear to the ground.

Objective-C is a rapidly evolving language, in a way that you just don't see in established programming languages. ARC, object literals, subscripting, blocks: in the span of just three years, so much of how we program in Objective-C has been changed (for the better).

All of this innovation is a result of Apple's philosophy of vertical integration. Just as Apple's investment in designing its own chipsets gave them leverage to compete aggressively with their mobile hardware, so too has their investment in LLVM allowed their software to keep pace.

Clang developments range from the mundane to paradigm-changing, but telling the difference takes practice. Because we're talking about low-level language features, it's difficult to understand what implications they may have higher up with API design.

One such example is instancetype, the subject of this week's article.


In Objective-C, conventions aren't just a matter of coding best-practices, they are implicit instructions to the compiler.

For example, alloc and init both have return types of id, yet in Xcode, the compiler makes all of the correct type checks. How is this possible?

In Cocoa, there is a convention that methods with names like alloc, or init always return objects that are an instance of the receiver class. These methods are said to have a related result type.

Class constructor methods, although they similarly return id, don't get the same type-checking benefit, because they don't follow that naming convention.

You can try this out for yourself:

[[[NSArrayalloc]init]mediaPlaybackAllowsAirPlay];// ❗ "No visible @interface for `NSArray` declares the selector `mediaPlaybackAllowsAirPlay`"[[NSArrayarray]mediaPlaybackAllowsAirPlay];// (No error)

Because alloc and init follow the naming convention for being a related result type, the correct type check against NSArray is performed. However, the equivalent class constructor array does not follow that convention, and is interpreted as id.

id is useful for opting-out of type safety, but losing it when you do want it sucks.

The alternative, of explicitly declaring the return type ((NSArray *) in the previous example) is a slight improvement, but is annoying to write, and doesn't play nicely with subclasses.

This is where the compiler steps in to resolve this timeless edge case to the Objective-C type system:

instancetype is a contextual keyword that can be used as a result type to signal that a method returns a related result type. For example:

@interfacePerson+(instancetype)personWithName:(NSString*)name;@end

instancetype, unlike id, can only be used as the result type in a method declaration.

With instancetype, the compiler will correctly infer that the result of +personWithName: is an instance of a Person.

Look for class constructors in Foundation to start using instancetype in the near future. New APIs, such as UICollectionViewLayoutAttributes are using instancetype already.

Further Implications

Language features are particularly interesting because, again, it's often unclear of what impact they'll have on higher-level aspects of software design.

While instancetype may seem to be a rather mundane, albeit welcome addition to the compiler, it can be used to some rather clever ends.

Jonathan Sterling wrote this quite interesting article, detailing how instancetype could be used to encode statically-typed collections, without generics:

NSURL<MapCollection>*sites=(id)[NSURLmapCollection];[sitesput:[NSURLURLWithString:@"http://www.jonmsterling.com/"]at:@"jon"];[sitesput:[NSURLURLWithString:@"http://www.nshipster.com/"]at:@"nshipster"];NSURL*jonsSite=[sitesat:@"jon"];// => http://www.jonmsterling.com/

Statically-typed collections would make APIs more expressive--no longer would a developer be unsure about what kinds of objects are allowed in a collection parameter.

Whether or not this becomes an accepted convention in Objective-C, it's fascinating to how a low-level feature like instancetype can be used to change shape of the language (in this case, making it look more like C#.


instancetype is just one of the many language extensions to Objective-C, with more being added with each new release.

Know it, love it.

And take it as an example of how paying attention to the low-level details can give you insights into powerful new ways to transform Objective-C.


CGGeometry

$
0
0

Unless you were a Math Geek or an Ancient Greek, Geometry was probably not your favorite subject in high school. No, chances are that you were that kid in class who dutifully programmed all of the necessary formulæ into your TI-8X calculator.

So for those of you who spent more time learning TI-BASIC than Euclidean geometry, here's the cheat-sheet for how geometry works in Quartz 2D, the drawing system used in iOS and Mac OS X:

  • A CGPoint is a struct that represents a point in a two-dimensional coordinate system. For iOS, the origin is at the top-left, so points move right and down as their x and y values, respectively, increase. OS X, by contrast, is oriented with (0, 0) in the bottom left, with y moving up as it increases.

  • A CGSize is a struct that represents the dimensions of width and height.

  • A CGRect is a struct with both a CGPoint (origin) and a CGSize (size), representing a rectangle drawn from its origin point with the width and height of its size.

Because CGRect is used to represent the frame of every view drawn on screen, a programmer's success in graphical programming is contingent on their ability to effectively manipulate rectangle geometry.

Fortunately for us, Quartz comes with a slew of useful functions to reduce the amount of floating point math we have to do ourselves. As central as view programming is to Cocoa, and as useful as these functions are, however, they remain relatively unknown to most iOS developers.

This will not stand! Let's shine some light on the most useful functions and save y'all some typing!


Transformations

First on our list are the geometric transformations. These functions return a CGRect, which is the result of performing a particular set of operations on the passed rectangle.

CGRectOffset

CGRectOffset: Returns a rectangle with an origin that is offset from that of the source rectangle.

CGRectCGRectOffset(CGRectrect,CGFloatdx,CGFloatdy)

Consider using this anytime you're changing the origin of a rectangle. Not only can it save a line of code when changing both the horizontal and vertical position, but more importantly, it represents the translation more semantically than manipulating the origin values individually.

CGRectInset

CGRectInset: Returns a rectangle that is smaller or larger than the source rectangle, with the same center point.

CGRectCGRectInset(CGRectrect,CGFloatdx,CGFloatdy)

Want to make a view-within-a-view look good? Give it a nice 10pt padding with CGRectInset. Keep in mind that the rectangle will be resized around its center by ± dx on its left and right edge (for a total of 2 × dx), and ± dy on its top and bottom edge (for a total of 2 × dy).

If you're using CGRectInset as a convenience function for resizing a rectangle, it is common to chain this with CGRectOffset by passing the result of CGRectInset as the rect argument in CGRectOffset.

CGRectIntegral

CGRectIntegral: Returns the smallest rectangle that results from converting the source rectangle values to integers.

CGRectCGRectIntegral(CGRectrect)

It's important that CGRect values all are rounded to the nearest whole point. Fractional values cause the frame to be drawn on a pixel boundary. Because pixels are atomic units (cannot be subdivided†) a fractional value will cause the drawing to be averaged over the neighboring pixels, which looks blurry.

CGRectIntegral will floor each origin value, and ceil each size value, which will ensure that your drawing code will crisply align on pixel boundaries.

As a rule of thumb, if you are performing any operations that could result in fractional point values (e.g. division, CGGetMid[X|Y], or CGRectDivide), use CGRectIntegral to normalize rectangles to be set as a view frame.

† Technically, since the coordinate system operates in terms of points, Retina screens, which have 4 pixels for every point, can draw ± 0.5f point values on odd pixels without blurriness.

Value Helper Functions

These functions provide a shorthand way to calculate interesting dimensional values about a particular CGRect.

CGRectGet[Min|Mid|Max][X|Y]

  • CGRectGetMinX
  • CGRectGetMinY
  • CGRectGetMidX
  • CGRectGetMidY
  • CGRectGetMaxX
  • CGRectGetMaxY

These six functions return the minimum, middle, or maximum x or y value for a rectangle, taking the form:

CGFloatCGRectGet[Min|Mid|Max][X|Y](CGRectrect)

These functions will replace code like frame.origin.x + frame.size.width with cleaner, more semantically expressive equivalents (especially with the mid and max functions).

CGRectGet[Width|Height]

CGRectGetHeight: Returns the height of a rectangle.

CGFloatCGRectGetHeight(CGRectrect)

CGRectGetWidth: Returns the width of a rectangle.

CGFloatCGRectGetWidth(CGRectrect)

Much like the previous functions, CGRectGetWidth& CGRectGetHeight are often preferable to returning the corresponding member of a CGRect's size. While it's not extremely competitive in terms of character savings, remember that semantic clarity trumps brevity every time.

Identities

There are three special rectangle values, each of which have unique properties that are important to know about:

CGRectZero, CGRectNull, & CGRectInfinite

  • const CGRect CGRectZero: A rectangle constant with location (0,0), and width and height of 0. The zero rectangle is equivalent to CGRectMake(0.0f, 0.0f, 0.0f, 0.0f).
  • const CGRect CGRectNull: The null rectangle. This is the rectangle returned when, for example, you intersect two disjoint rectangles. Note that the null rectangle is not the same as the zero rectangle.
  • const CGRect CGRectInfinite: A rectangle that has infinite extent.

CGRectZero is perhaps the most useful of all of the special rectangle values. When initializing subviews, their frames are often initialized to CGRectZero, deferring their layout to -layoutSubviews.

CGRectNull is distinct from CGRectZero, despite any implied correspondence to NULL == 0. This value is conceptually similar to NSNotFound, in that it represents the absence of an expected value. Be aware of what functions can return CGRectNull, and be prepared to handle it accordingly, by testing with CGRectIsNull.

CGRectInfinite is the most exotic of all, and has some of the most interesting properties. It intersects with all points and rectangles, contains all rectangles, and its union with any rectangle is itself. Use CGRectIsInfinite to check to see if a rectangle is infinite.

And Finally...

Behold, the most obscure, misunderstood, and useful of the CGGeometry functions: CGRectDivide.

CGRectDivide

CGRectDivide: Divides a source rectangle into two component rectangles.

voidCGRectDivide(CGRectrect,CGRect*slice,CGRect*remainder,CGFloatamount,CGRectEdgeedge)

CGRectDivide divides a rectangle into two components in the following way:

  • Take a rectangle and choose an edge (left, right, top, or bottom).
  • Measure out an amount from that edge.
  • Everything from the edge to the measured amount is stored in the rectangle referenced in the slice argument.
  • The rest of the original rectangle is stored in the remainder out argument.

That edge argument takes a value from the CGRectEdge enum:

enumCGRectEdge{CGRectMinXEdge,CGRectMinYEdge,CGRectMaxXEdge,CGRectMaxYEdge}

CGRectDivide is perfect for dividing up available space among several views (call it on subsequent remainder amounts to accommodate more than two views). Give it a try next time you're manually laying-out a UITableViewCell.


So what if you didn't pay attention in Geometry class--this is the real world, and in the real world, you have CGGeometry.h

Know it well, and you'll be on your way to discovering great new user interfaces in your apps. Do good enough of a job with that, and you may run into the greatest arithmetic problem of all: adding up all of the money you'll make with your awesome new app. Mathematical!

Reader Submissions - New Year's 2013

$
0
0

In celebration of the forthcoming year++, I thought it'd be fun to compile a list of some of your favorite tips and tricks of the trade--to give y'all a chance to show off some of your NSHipster cred.

Thanks to Cédric Luthi, Jason Kozemczak, Jeff Kelley, Joel Parsons, Maximilian Tagher, Rob Mayoff, Vadim Shpakovski, & @alextud for answering the call with excellent submissions.

Associated Objects in Categories

This first tip is so nice it was mentioned twice, both by Jason Kozemczak& Jeff Kelley.

Categories are a well-known feature of Objective-C, allowing new methods to be added to existing classes. Much less well known is that with some objc runtime hacking, you can add new properties as well. Observe!

NSObject+IndieBandName.h

@interfaceNSObject(IndieBandName)@property(nonatomic,strong)NSString*indieBandName;@end

NSObject+IndieBandName.m

#import "NSObject+Extension.h"#import <objc/runtime.h>staticconstvoid*IndieBandNameKey=&IndieBandNameKey;@implementationNSObject(IndieBandName)@dynamicindieBandName;-(NSString*)indieBandName{returnobjc_getAssociatedObject(self,IndieBandNameKey);}-(void)setIndieBandName:(NSString*)indieBandName{objc_setAssociatedObject(self,IndieBandNameKey,indieBandName,OBJC_ASSOCIATION_RETAIN_NONATOMIC);}@end

This way, all of your objects can store and retrieve the name of their band, which--by the way--is performing this Wednesday night, and you should totally come.

While this is a cool trick and all, it should only be used as a method of last resort. Before you go this route, ask yourself if a particular property can't either be derived from existing values, or should be managed by another class.

A good example of an associated object is how AFNetworking adds a property for an image request operation in its UIImageView category.

LLDB View Hierarchy Dump

Rob Mayoff responded with an obscure and powerful incantation to make debugging views a delight. Create .lldbinit in your home directory, if it doesn't already exist, and add the following:

~/.lldbinit

command regex rd 's/^[[:space:]]*$/po [[[UIApplication sharedApplication] keyWindow] recursiveDescription]/' 's/^(.+)$/po [%1 recursiveDescription]/'

Now you can get a recursive hierarchy of any view in your iOS application with the LLDB debugger. You can try this for yourself by setting a breakpoint in a view controller, and type rd self.view. You may be surprised by what's under the hood with some of the built-in UI controls!

LLDB Print Contents of a CGPathRef

While we're on the subject of LLDB, Rob Mayoff sent in a useful incantation for printing out the contents of a CGPathRef from the debugger:

p (void)CGPathPrint(pathRef, 0)

If you're doing any kind of complex Core Graphics drawing, be sure to keep this one handy.

Use +initialize, Not +load

Vadim Shpakovski wrote in with some advice about class loading and initialization. There are two magical class methods in Objective-C: +load and +initialize, which are automatically called by virtue of the class being used. The difference between the two methods, however, has significant performance implications for your application.

Mike Ash has a great explanation of this:

+load is invoked as the class is actually loaded, if it implements the method. This happens very early on. If you implement +load in an application or in a framework that an application links to, +load will run before main(). If you implement +load in a loadable bundle, then it runs during the bundle loading process.

The +initialize method is invoked in a more sane environment and is usually a better place to put code than +load. +initialize is interesting because it's invoked lazily and may not be invoked at all. When a class first loads, +initialize is not called. When a message is sent to a class, the runtime first checks to see if +initialize has been called yet. If not, it calls it before proceeding with the message send.

tl;dr: Implement +initialize, not +load, if you need this automatic behavior.

Xcode Snippets

Maximilian Tagher gave a shout-out to the benefits of Xcode Snippets.

Great developers take pride in knowing their tools, and being able to use them to maximum effect. For better or for worse, this means knowing Xcode like the back of our hand. Verbose as Objective-C is, "do more by typing less" rings especially true as a productivity mantra, and Xcode Snippets are one of the best ways to do this.

If you're looking for a place to start, try downloading and forking these Xcode Snippets.

Macro for Measuring Execution Time

Here's a helpful macro for easily measuring the elapsed time for executing a particular block of code, sent in from @alextud:

NS_INLINEvoidMVComputeTimeWithNameAndBlock(constchar*caller,void(^block)()){CFTimeIntervalstartTimeInterval=CACurrentMediaTime();block();CFTimeIntervalnowTimeInterval=CACurrentMediaTime();NSLog(@"%s - Time Running is: %f",caller,nowTimeInterval-startTimeInterval);}#define MVComputeTime(...) MVComputeTimeWithNameAndBlock(__PRETTY_FUNCTION__, (__VA_ARGS__))

Block Enumeration Methods

Joel Parsons submitted a great tip about using -enumerateObjectsWithOptions:usingBlock: in NSArray and other collection classes. By passing the NSEnumerationConcurrent option, you can get significant performance benefits over NSFastEnumeration's for...in-style enumeration by executing the block concurrently.

However, be warned! Not all enumerations lend themselves to concurrent execution, so don't go around replacing all of your for...in blocks with NSEnumerationConcurrent willy-nilly, unless random crashing is something you like in an app.

Reverse-Engineered Implementation of NSString Equality Methods

Displaying his characteristic brilliance and familiarity of Cocoa internals Cédric Luthi submitted a reverse-engineered implementation of the NString equality methods. Fascinating!

Animate NSLayoutConstraint.constant

This one goes out to all you fans of Cocoa Auto Layout, from Vadim Shpakovski:

viewConstraint.constant=<#ConstantValueFrom#>;[viewlayoutIfNeeded];viewConstraint.constant=<#ConstantValueTo#>;[viewsetNeedsUpdateConstraints];[UIViewanimateWithDuration:ConstantAnimationDurationanimations:^{[viewlayoutIfNeeded];}];

Attentive readers may have already noted this, but the code above would make an excellent Xcode Snippet, by the way.

Printing NSCache Usage

Finishing up this batch of tips and tricks is Cédric Luthi again, this time unearthing the private method cache_print as a way to get some visibility into NSCache:

externvoidcache_print(void*cache);-(void)printCache:(NSCache*)cache{cache_print(*((void**)(__bridgevoid*)cache+3));}

This code sample has only been tested on iOS, and should only be used for debugging (i.e. take this out before submitting to Apple!).


Thanks again to everyone for their submissions this time around. We'll definitely be doing this again, so feel free to send your favorite piece of Objective-C trivia, framework arcana, hidden Xcode feature, or anything else you think is cool to @NSHipster!

And thank you, dear reader, for your support of NSHipster over these last wonderful months. We have a lot of insanely great things planned for NSHipster in 2013, and we look forward to being able to share it all with all of you.

nil / Nil / NULL / NSNull

$
0
0

Understanding the concept of nothingness is as much a philosophical issue as it is a pragmatic one. We are inhabitants of a universe of somethings, yet reason in a logical universe of existential uncertainties. As a physical manifestation of a logical system, computers are faced with the intractable problem of how to represent nothing with something.

In Objective-C, there are several different varieties of nothing. The reason for this goes back to a common NSHipster refrain, of how Objective-C bridges the procedural paradigm of C with Smalltalk-inspired object-oriented paradigm.

C represents nothing as 0 for primitive values, and NULL for pointers (which is equivalent to 0 in a pointer context).

Objective-C builds on C's representation of nothing by adding nil. nil is an object pointer to nothing. Although semantically distinct from NULL, they are technically equivalent to one another.

On the framework level, Foundation defines NSNull, which defines a class method, +null, which returns the singleton NSNull object. NSNull is different from nil or NULL, in that it is an actual object, rather than a zero value.

Additionally, in Foundation/NSObjCRuntime.h, Nil is defined as a class pointer to nothing. This lesser-known title-case cousin of nil doesn't show up much very often, but it's at least worth noting.

There's Something About nil

Newly-alloc'd NSObjects start life with their contents set to 0. This means that all pointers that object has to other objects begin as nil, so it's unnecessary to, for instance, set self.(association) = nil in init methods.

Perhaps the most notable behavior of nil, though, is that it can have messages sent to it.

In other languages, like C++, this would crash your program, but in Objective-C, invoking a method on nil returns a zero value. This greatly simplifies expressions, as it obviates the need to check for nil before doing anything:

// For example, this expression...if(name!=nil&&[nameisEqualToString:@"Steve"]){...}// ...can be simplified to:if([nameisEqualToString:@"steve"]){...}

Being aware of how nil works in Objective-C allows this convenience to be a feature, and not a lurking bug in your application. Make sure to guard against cases where nil values are unwanted, either by checking and returning early to fail silently, or adding a NSParameterAssert to throw an exception.

NSNull: Something for Nothing

NSNull is used throughout Foundation and other frameworks to skirt around the limitations of collections like NSArray and NSDictionary not being able to contain nil values. You can think of NSNull as effectively boxing the NULL or nil value so that it can be used in collections:

NSMutableDictionary*mutableDictionary=[NSMutableDictionarydictionary];mutableDictionary[@"someKey"]=[NSNullnull];// Sets value of NSNull singleton for `someKey`NSLog(@"Keys: %@",[mutableDictionaryallKeys]);// @[@"someKey"]

So to recap, here are the four values representing nothing that every Objective-C programmer should know about:

SymbolValueMeaning
NULL(void *)0literal null value for C pointers
nil(id)0literal null value for Objective-C objects
Nil(Class)0literal null value for Objective-C classes
NSNull[NSNull null]singleton object used to represent null

__attribute__

$
0
0

A recurring theme of this publication has been the importance of a healthy relationship with the compiler. Like any craft, one's effectiveness as a practitioner is contingent on how they treat their tools. Take good care of them, and they'll take good care of you.

__attribute__ is a compiler directive that specifies characteristics on declarations, which allows for more error checking and advanced optimizations.

The syntax for this keyword is __attribute__ followed by two sets of parentheses (the double parentheses makes it easy to "macro out", especially with multiple attributes). Inside the parentheses is a comma-delimited list of attributes. __attribute__ directives are placed after function, variable, and type declarations.

// Return the square of a numberintsquare(intn)__attribute__((const));// Declare the availability of a particular APIvoidf(void)__attribute__((availability(macosx,introduced=10.4,deprecated=10.6)));// Send printf-like message to stderr and exitexternvoiddie(constchar*format,...)__attribute__((noreturn,format(printf,1,2)));

If this is starting to remind you of ISO C's #pragma, you're not alone.

In fact, when __attribute__ was first introduced to GCC, it was faced with some resistance by some who suggested that #pragma be used exclusively for the same purposes.

There are, however, two very good reasons why __attribute__ exists:

  1. It is impossible to generate #pragma commands from a macro.
  2. There is no telling what the same #pragma might mean in another compiler.

Quoth the GCC Documentation for Function Attributes:

These two reasons applied to almost any application that might have been proposed for #pragma. It was basically a mistake to use #pragma for anything.

Indeed, if you look at modern Objective-C--in the headers of Apple frameworks and well-engineered open-source projects--__attribute__ is used for myriad purposes. (By contrast, #pragma's main claim to fame these days is decoration: #pragma mark)

So without further ado, let's take a look at the most important attributes:


GCC

format

The format attribute specifies that a function takes printf, scanf, strftime or strfmon style arguments which should be type-checked against a format string.

externintmy_printf(void*my_object,constchar*my_format,...)__attribute__((format(printf,2,3)));

Objective-C programmers can also use the __NSString__ format to enforce the same rules as format strings in NSString +stringWithFormat: and NSLog().

nonnull

The nonnull attribute specifies that some function parameters should be non-null pointers.

externvoid*my_memcpy(void*dest,constvoid*src,size_tlen)__attribute__((nonnull(1,2)));

Using nonnull encodes expectations about values into an explicit contract, which can help catch any NULL pointer bugs lurking in any calling code. Remember: compile-time errors ≫ run-time errors.

noreturn

A few standard library functions, such as abort and exit, cannot return. GCC knows this automatically. The noreturn attribute specifies this for any other function that never returns.

For example, AFNetworking uses the noreturn attribute for its network request thread entry point method. This method is used when spawning the dedicated network NSThread to ensure that the detached thread continues execution for the lifetime of the application.

pure / const

The pure attribute specifies that a function has no effects except the return value, such that their return value depends only on the parameters and/or global variables. Such a function can be subject to common subexpression elimination and loop optimization just as an arithmetic operator would be.

The const attribute specifies that a function does not examine any values except their arguments, and have no effects except the return value. Note that a function that has pointer arguments and examines the data pointed to must not be declared const. Likewise, a function that calls a non-const function usually must not be const. It does not make sense for a const function to return void.

intsquare(intn)__attribute__((const));

pure and const are both attributes that invoke a functional programming paradigm in order to allow for significant performance optimizations. const can be thought as a stricter form of pure since it doesn't depend on global values or pointers.

For example, because the result of a function declared const does not depend on anything other than the arguments passed in, the result of the function can cache that result and return any time the function is called with that same combination of arguments. (i.e. we know that the square of a number is constant, so we only need to compute it once).

unused

This attribute, attached to a function, means that the function is meant to be possibly unused. GCC will not produce a warning for this function.

The same effect can be accomplished with the __unused keyword. Declare this on parameters that are not used in the method implementation. Knowing that little bit of context allows the compiler to make optimizations accordingly. You're most likely to use __unused in delegate method implementations, since protocols frequently provide more context than is often necessary, in order to satisfy a large number of potential use cases.

LLVM

Like many features of GCC, Clang supports __attribute__, adding its own small set of extensions.

To check the availability of a particular attribute, you can use the __has_attribute directive.

availability

Clang introduces the availability attribute, which can be placed on declarations to describe the lifecycle of that declaration relative to operating system versions. Consider the function declaration for a hypothetical function f:

voidf(void)__attribute__((availability(macosx,introduced=10.4,deprecated=10.6,obsoleted=10.7)));

The availability attribute states that f was introduced in Mac OS X 10.4, deprecated in Mac OS X 10.6, and obsoleted in Mac OS X 10.7.

This information is used by Clang to determine when it is safe to use f: for example, if Clang is instructed to compile code for Mac OS X 10.5, a call to f() succeeds. If Clang is instructed to compile code for Mac OS X 10.6, the call succeeds but Clang emits a warning specifying that the function is deprecated. Finally, if Clang is instructed to compile code for Mac OS X 10.7, the call fails because f() is no longer available.

The availability attribute is a comma-separated list starting with the platform name and then including clauses specifying important milestones in the declaration's lifetime (in any order) along with additional information.

  • introduced: The first version in which this declaration was introduced.
  • deprecated: The first version in which this declaration was deprecated, meaning that users should migrate away from this API.
  • obsoleted: The first version in which this declaration was obsoleted, meaning that it was removed completely and can no longer be used.
  • unavailable: This declaration is never available on this platform.
  • message Additional message text that Clang will provide when emitting a warning or error about use of a deprecated or obsoleted declaration. Useful to direct users to replacement APIs.

Multiple availability attributes can be placed on a declaration, which may correspond to different platforms. Only the availability attribute with the platform corresponding to the target platform will be used; any others will be ignored. If no availability attribute specifies availability for the current target platform, the availability attributes are ignored.

Supported Platforms:

  • ios: Apple’s iOS operating system. The minimum deployment target is specified by the -mios-version-min=*version* or -miphoneos-version-min=*version* command-line arguments.
  • macosx: Apple’s Mac OS X operating system. The minimum deployment target is specified by the -mmacosx-version-min=*version* command-line argument.

overloadable

Clang provides support for C++ function overloading in C. Function overloading in C is introduced using the overloadable attribute. For example, one might provide several overloaded versions of a tgsin function that invokes the appropriate standard function computing the sine of a value with float, double, or long double precision:

#include <math.h>float__attribute__((overloadable))tgsin(floatx){returnsinf(x);}double__attribute__((overloadable))tgsin(doublex){returnsin(x);}longdouble__attribute__((overloadable))tgsin(longdoublex){returnsinl(x);}

Note that overloadable only works for functions. You can overload method declarations to some extent by using generic return and parameter types, like id and void *.


Context is king when it comes to compiler optimizations. By providing constraints on how to interpret your code, you're increases the chance that the generated code is as efficient as possible. Meet your compiler half-way, and you'll always be rewarded.

And __attribute__ isn't just for the compiler either: The next person to see the code will appreciate the extra context, too. So go the extra mile for the benefit of your collaborator, successor, or just 2-years-from-now-(and-you've-forgotten-everything-about–this-code) you.

Because in the end, the love you take is equal to the love you make.

NSLocalizedString

$
0
0

Strings are perhaps the most versatile data type in computing. They're passed around as symbols, used to encode numeric values, associate values to keys, represent resource paths, store linguistic content, and format information. Having a strong handle on user-facing strings is essential to making a great user experience.

In Foundation, there is a convenient macro for denoting strings as user-facing: NSLocalizedString.

NSLocalizedString provides string localization in "compile-once / run everywhere" fashion, replacing all localized strings with their respective translation according to the string tables of the user settings. But even if you're not going to localize your app to any other markets, NSLocalizedString does wonders with respect to copy writing & editing.

For more information about Localization (l10n) and Internationalization (i18n) see the NSHipster article about NSLocale.


NSLocalizedString is a Foundation macro that returns a localized version of a string. It has two arguments: key, which uniquely identifies the string to be localized, and comment, a string that is used to provide sufficient context for accurate translation.

In practice, the key is often just the base translation string to be used, while comment is usually nil, unless there is an ambiguous context:

textField.placeholder=NSLocalizedString(@"Username",nil);

NSLocalizedString can also be used as a format string in NSString +stringWithFormat:. In these cases, it's important to use the comment argument to provide enough context to be properly translated.

self.title=[NSStringstringWithFormat:NSLocalizedString(@"%@'s Profile",@"{User First Name}'s Profile"),user.name];
label.text=[NSStringstringWithFormat:NSLocalizedString(@"Showing %lu of %lu items",@"Showing {number} of {total number} items"),[pagecount],[itemscount]];

NSLocalizedString& Co.

There are four varieties of NSLocalizedString, with increasing levels of control (and obscurity):

NSString*NSLocalizedString(NSString*key,NSString*comment)
NSString*NSLocalizedStringFromTable(NSString*key,NSString*tableName,NSString*comment)
NSString*NSLocalizedStringFromTableInBundle(NSString*key,NSString*tableName,NSBundle*bundle,NSString*comment)
NSString*NSLocalizedStringWithDefaultValue(NSString*key,NSString*tableName,NSBundle*bundle,NSString*value,NSString*comment)

99% of the time, NSLocalizedString will suffice. If you're working in a library or shared component, NSLocalizedStringFromTable should be used instead.

Localizable.strings

At runtime, NSLocalizedString determines the preferred language, and finds a corresponding Localizable.strings file in the app bundle. For example, if the user prefers French, the file fr.lproj/Localizable.strings will be consulted.

Here's what that looks like:

/* No comment provided by engineer. */
"Username"="nom d'utilisateur";
/* {User First Name}'s Profile */
"%@'s Profile"="profil de %1$@";

Localizable.strings files are initially generated with genstrings.

The genstrings utility generates a .strings file(s) from the C or Objective-C (.c or .m) source code file(s) given as the argument(s). A .strings file is used for localizing an application for different languages, as described under "Internationalization" in the Cocoa Developer Documentation.

genstrings goes through each of the selected source files, and for each use of NSLocalizedString, appends the key and comment into a target file. It's up to the developer to then create a copy of that file for each targeted locale and have a localizer translate it.

No Madlibs

After reading that part about localized format strings, you may be tempted to take a clever, DRY approach by creating reusable grammar templates like `@"{Noun} {Verb} {Noun}", and localizing each word individually...

DON'T. This cannot be stressed enough: don't subdivide localized strings. Context will be lost, grammatical constructions will be awkward and unidiomatic, verbs will be incorrectly conjugated, and you'll have missed the point entirely—taking great effort to make something worse than if you hadn't bothered in the first place.

Numbers, dates, and similar values are almost always safe replacements. Nouns are subject to pluralization and verb conjugation, but usually safe as direct or indirect objects.

For additional guidelines, see Localizing String Resources from Apple's Internationalization Programming guide.


NSLocalizedString is a remarkably reliable indicator of code quality. Those who care enough to take a few extra seconds to internationalize are very likely to be just as thoughtful when it comes to design and implementation.

Always wrap user-facing strings with NSLocalizedString.

Even if you don't plan to localize your app into any other languages, there is immense utility in being able to easily review all of the strings that a user will see. And if localization is in the cards, it's significantly easier to NSLocalize your strings as you go along the first time, then try to find all of them after-the-fact.

Viewing all 382 articles
Browse latest View live