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

NSValue

$
0
0

As part of playing the role of Abraham Lincoln in the eponymous 2012 biopic, Daniel Day-Lewis would insist on walking through a refrigerator box marked "TIME MACHINE" anytime he entered or left the set. True Story.

While the ends certainly justify the means when it comes to Mr. Day-Lewis' method acting, one can't help but marvel at the absurdity of a magical cardboard box used as a nexus between the modern and historical worlds.

Yet, this is exactly what we do as Objective-C programmers.

...well not exactly, but there is a box involved.

As mentioned time and again in NSHipster, what makes Objective-C such a curiosity is the way it merges the old, procedural world of C with the modern Object-Oriented influences of Smalltalk. When done correctly, this tension can be exploited to craft semantically rich software without sacrificing performance. But bridging that gap between old and new is a miasma of casts, bridges, and of course, boxes.

Boxing is the process of encapsulating scalars (int, double, BOOL, etc.) and value types (struct, enum) with an object container, and is primarily used to store those values in collection objects—namely arrays and dictionaries.

NSNumber is often used to box scalars, but in Foundation, the reigning featherweight champion of boxing is NSValue.


NSValue is a simple container for a single C or Objective-C data value. It can hold scalars and value types, as well as pointers and object IDs.

While boxing is an admittedly dry subject matter, there are two methods in particular that are worth noting: +valueWithBytes:objCType:, which serves as a primer for working with NSValue, and +valueWithNonretainedObject:, which is surprisingly useful for being relatively unknown.

valueWithBytes:objCType:

+valueWithBytes:objCType: Creates and returns an NSValue object that contains a given value, which is interpreted as being of a given Objective-C type.

  • value: The value for the new NSValue object.
  • type: The Objective-C type of value. type should be created with the Objective-C @encode() compiler directive; it should not be hard-coded as a C string.

@encode was discussed in our rundown of the myriad @ Compiler Directives:

@encode(): Returns the type encoding of a type. This type value can be used as the first argument encode in NSCoder -encodeValueOfObjCType:at.

The subject of type encodings would make for a great article of its own, but the main takeaway is that it serves as a terse, human-readable representation of the structure of a type. For example,

typedefstructexample{idanObject;char*aString;intanInt;}Example;

...has the encoding:

{example=@*i}

NSValue uses this type encoding to create the necessary data structures to represent these values internally. Neat!

valueWithNonretainedObject:

+valueWithNonretainedObject: Creates and returns an NSValue object that contains a given object.

anObject: The value for the new object.

If you already knew about valueWithNonretainedObject, you should be nodding with a knowing grin. If you didn't, you're likely staring incredulously with mouth agape. Or if not, you will be soon.

In short, valueWithNonretainedObject: allows objects to be added to a collection, without the need for satisfying <NSCopying>.

It's something that comes up occasionally, working with objects that can't be directly added to an NSArray or NSDictionary. Without knowing about valueWithNonretainedObject:, this would be something that would throw off your entire game—especially if you're just starting out in Objective-C.

But now you're in the know. You won't be stifled by such pedestrian concerns. You need not grope around for answers with NSPointerArray or NSMapTable. Today is a new day.


Having unpacked all of this wisdom about NSValue, you can now face that cruel divide between procedural and object-oriented; C and Smalltalk. Because everything is easy with a magic box.


Type Encodings

$
0
0

From number stations and numerology to hieroglyphs and hobo codes, there is something truly fascinating about finding meaning that hides in plain sight. Though hidden messages in and of themselves are rarely useful or particularly interesting, it's the thrill of the hunt that piques our deepest curiosities.

It is in this spirit that we take a look at Objective-C Type Encodings in this week's edition of NSHipster.


Last week, in a discussion about NSValue, there was mention of +valueWithBytes:objCType:, whose second parameter should be created with the Objective-C @encode() compiler directive.

@encode, one of the @ Compiler Directives, returns a C string that encodes the internal representation of a given type (e.g., @encode(int)i), similar to the ANSI C typeof operator. Apple's Objective-C runtime uses type encodings internally to help facilitate message dispatching.

Here's a rundown of all of the different Objective-C Type Encodings:

Objective-C Type Encodings
CodeMeaning
cA char
iAn int
sA short
lA longl is treated as a 32-bit quantity on 64-bit programs.
qA long long
CAn unsigned char
IAn unsigned int
SAn unsigned short
LAn unsigned long
QAn unsigned long long
fA float
dA double
BA C++ bool or a C99 _Bool
vA void
*A character string (char *)
@An object (whether statically typed or typed id)
#A class object (Class)
:A method selector (SEL)
[array type] An array
{name=type...}A structure
(name=type...)A union
bnumA bit field of num bits
^typeA pointer to type
?An unknown type (among other things, this code is used for function pointers)

Of course, charts are fine, but experimenting in code is even better:

NSLog(@"int        : %s",@encode(int));NSLog(@"float      : %s",@encode(float));NSLog(@"float *    : %s",@encode(float*));NSLog(@"char       : %s",@encode(char));NSLog(@"char *     : %s",@encode(char*));NSLog(@"BOOL       : %s",@encode(BOOL));NSLog(@"void       : %s",@encode(void));NSLog(@"void *     : %s",@encode(void*));NSLog(@"NSObject * : %s",@encode(NSObject*));NSLog(@"NSObject   : %s",@encode(NSObject));NSLog(@"[NSObject] : %s",@encode(typeof([NSObjectclass])));NSLog(@"NSError ** : %s",@encode(typeof(NSError**)));intintArray[5]={1,2,3,4,5};NSLog(@"int[]      : %s",@encode(typeof(intArray)));floatfloatArray[3]={0.1f,0.2f,0.3f};NSLog(@"float[]    : %s",@encode(typeof(floatArray)));typedefstruct_struct{shorta;longlongb;unsignedlonglongc;}Struct;NSLog(@"struct     : %s",@encode(typeof(Struct)));

Result:

int        : i
float      : f
float *    : ^f
char       : c
char *     : *
BOOL       : c
void       : v
void *     : ^v

NSObject * : @
NSObject   : #
[NSObject] : {NSObject=#}
NSError ** : ^@

int[]      : [5i]
float[]    : [3f]
struct     : {_struct=sqQ}

There are some interesting takeaways from this:

  • Whereas the standard encoding for pointers is a preceding ^, char * gets its own code: *. This makes sense conceptually, as C strings are thought to be entities in and of themselves, rather than a pointer to something else.
  • BOOL is c, rather than i, as one might expect. Reason being, char is smaller than an int, and when Objective-C was originally designed in the 80's, bits (much like the dollar) were more valuable than they are today. BOOL is specifically a signed char (even if -funsigned-char is set), to ensure a consistent type between compilers, since char could be either signed or unsigned.
  • Passing NSObject directly yields #. However, passing [NSObject class] yields a struct named NSObject with a single class field. That is, of course, the isa field, which all NSObject instances have to signify their type.

Method Encodings

As mentioned in Apple's "Objective-C Runtime Programming Guide", there are a handful of type encodings that are used internally, but cannot be returned with @encode.

These are the type qualifiers for methods declared in a protocol:

Objective-C Method Encodings
CodeMeaning
rconst
nin
Ninout
oout
Obycopy
Rbyref
Voneway

For anyone familiar with NSDistantObject, you'll doubtless recognize these as a vestige of Distributed Objects.

Although DO has fallen out of fashion in the age of iOS, it was an interprocess messaging protocol used between Cocoa applications--even running on different machines on the network. Under these constraints, there were benefits to be had from the additional context.

For example, parameters in distributed object messages were passed as proxies by default. In situations where proxying would be unnecessarily inefficient, the bycopy qualifier could be added to make sure a full copy of the object was sent. Also by default, parameters were inout, signifying that objects needed to be sent back and forth when sending the message. By specifying a parameter as in or out instead, the application could avoid the round-trip overhead.


So what do we gain from our newfound understanding of Objective-C Type Encodings?
Honestly, not that much (unless you're doing any crazy metaprogramming).

But as we said from the very outset, there is wisdom in the pursuit of deciphering secret messages.

Looking at type encodings reveals details about Objective-C runtime internals, which is a noble pursuit in and of itself. Going further down the rabbit hole, and we come to the secret history of Distributed Objects, and the obscure parameter qualifiers that still linger around to this day.

NSURLCache

$
0
0

NSURLCache provides a composite in-memory and on-disk caching mechanism for URL requests to your application. As part of Foundation's URL Loading System, any request loaded through NSURLConnection will be handled by NSURLCache.

Network caching reduces the number of requests that need to be made to the server, and improve the experience of using an application offline or under slow network conditions.

When a request has finished loading its response from the server, a cached response will be saved locally. The next time the same request is made, the locally-cached response will be returned immediately, without connecting to the server. NSURLCache returns the cached response automatically and transparently.

In order to take advantage of NSURLCache, a shared URL cache must be initialized and set. This should be done in -application:didFinishLaunchingWithOptions: on iOS, or –applicationDidFinishLaunching: on Mac OS X:

-(BOOL)application:(UIApplication*)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions{NSURLCache*URLCache=[[NSURLCachealloc]initWithMemoryCapacity:4*1024*1024diskCapacity:20*1024*1024diskPath:nil];[NSURLCachesetSharedURLCache:URLCache];}

Caching policies are specified in both the request (by the client) and in the response (by the server). Understanding these policies and how they relate to one another is essential to finding the optimal behavior for your application.

NSURLRequestCachePolicy

NSURLRequest has a cachePolicy property, which specifies the caching behavior of the request according to the following constants:

  • NSURLRequestUseProtocolCachePolicy: Caching logic defined in the protocol implementation is used for a particular URL load request. This is the default policy.
  • NSURLRequestReloadIgnoringLocalCacheData: Data should be loaded from the originating source. No existing cache data should be used.
  • NSURLRequestReloadIgnoringLocalAndRemoteCacheData: Not only should the local cache data be ignored, but proxies and other intermediates should be instructed to disregard their caches so far as the protocol allows.
  • NSURLRequestReturnCacheDataElseLoad: Existing cached data should be used, regardless of its age or expiration date. If there is no existing data in the cache corresponding to the request, the data is loaded from the originating source.
  • NSURLRequestReturnCacheDataDontLoad: Existing cache data should be used, regardless of its age or expiration date. If there is no existing data in the cache corresponding to the request, no attempt is made to load the data from the originating source, and the load is considered to have failed, (i.e. "offline" mode).
  • NSURLRequestReloadRevalidatingCacheData: Existing cache data may be used provided the origin source confirms its validity, otherwise the URL is loaded from the origin source.

It may not surprise you that these values are poorly understood and often confused with one another.

Adding to the confusion is the fact that NSURLRequestReloadIgnoringLocalAndRemoteCacheData and NSURLRequestReloadRevalidatingCacheDataaren't even implemented! (Link to Radar).

So here's what you actually need to know about NSURLRequestCachePolicy:

ConstantMeaning
UseProtocolCachePolicyDefault behavior
ReloadIgnoringLocalCacheDataDon't use the cache
ReloadIgnoringLocalAndRemoteCacheDataSeriously, don't use the cache
ReturnCacheDataElseLoadUse the cache (no matter how out of date), or if no cached response exists, load from the network
ReturnCacheDataDontLoadOffline mode: use the cache (no matter how out of date), but don't load from the network
ReloadRevalidatingCacheDataValidate cache against server before using

HTTP Cache Semantics

Because NSURLConnection is designed to support multiple protocols—including both FTP and HTTP/HTTPS—the URL Loading System APIs specify caching in a protocol-agnostic fashion. For the purposes of this article, caching will be explained in terms of HTTP semantics.

HTTP requests and responses use headers to communicate metadata such as character encoding, MIME type, and caching directives.

Request Cache Headers

By default, NSURLRequest will use the current time to determine whether a cached response should be returned. For more precise cache control, the following headers can be specified:

  • If-Modified-Since - This request header corresponds to the Last-Modified response header. Set the value of this to the Last-Modified value received from the last request to the same endpoint.
  • If-None-Match - This request header corresponds to the Etag response header. Use the Etag value received previously for the last request to that endpoint.

Response Cache Headers

An NSHTTPURLResponse contains a set of HTTP headers, which can include the following directives for how that response should be cached:

  • Cache-Control - This header must be present in the response from the server to enable HTTP caching by a client. The value of this header may include information like its max-age (how long to cache a response), and whether the response may be cached with public or private access, or no-cache (not at all). See the Cache-Control section of RFC 2616 for full details.

In addition to Cache-Control, a server may send additional headers that can be used to conditionally request information as needed (as mentioned in the previous section):

  • Last-Modified - The value of this header corresponds to the date and time when the requested resource was last changed. For example, if a client requests a timeline of recent photos, /photos/timeline, the Last-Modified value could be set to when the most recent photo was taken.
  • Etag - An abbreviation for "entity tag", this is an identifier that represents the contents requested resource. In practice, an Etag header value could be something like the MD5 digest of the resource properties. This is particularly useful for dynamically generated resources that may not have an obvious Last-Modified value.

NSURLConnectionDelegate

Once the server response has been received, the NSURLConnection delegate has an opportunity to specify the cached response in -connection:willCacheResponse:.

NSCachedURLResponse is a class that contains both an NSURLResponse with the cached NSData associated with the response.

In -connection:willCacheResponse:, the cachedResponse object has been automatically created from the result of the URL connection. Because there is no mutable counterpart to NSCachedURLResponse, in order to change anything about cachedResponse, a new object must be constructed, passing any modified values into –initWithResponse:data:userInfo:storagePolicy:, for instance:

-(NSCachedURLResponse*)connection:(NSURLConnection*)connectionwillCacheResponse:(NSCachedURLResponse*)cachedResponse{NSMutableDictionary*mutableUserInfo=[[cachedResponseuserInfo]mutableCopy];NSMutableData*mutableData=[[cachedResponsedata]mutableCopy];NSURLCacheStoragePolicystoragePolicy=NSURLCacheStorageAllowedInMemoryOnly;// ...return[[NSCachedURLResponsealloc]initWithResponse:[cachedResponseresponse]data:mutableDatauserInfo:mutableUserInfostoragePolicy:storagePolicy];}

If -connection:willCacheResponse: returns nil, the response will not be cached.

-(NSCachedURLResponse*)connection:(NSURLConnection*)connectionwillCacheResponse:(NSCachedURLResponse*)cachedResponse{returnnil;}

When left unimplemented, NSURLConnection will simply use the cached response that would otherwise be passed into -connection:willCacheResponse:, so unless you need to change or prevent caching, this method does not need to be implemented in the delegate.

Caveats

Just like its unrelated-but-similarly-named cohort, NSCache, NSURLCache is not without some peculiarities.

As of iOS 5, disk caching is supported, but only for HTTP, not HTTPS, requests (though iOS 6 added support for this). Peter Steinberger wrote an excellent article on this subject, after digging into the internals while implementing his own NSURLCache subclass.

Another article by Daniel Pasco at Black Pixel describes some unexpected default behavior when communicating with servers that don't set cache headers.


NSURLCache reminds us of how important it is to be familiar with the systems we interact with. Chief among them when developing for iOS or Mac OS X is, of course, the URL Loading System.

Untold numbers of developers have hacked together an awkward, fragile system for network caching functionality, all because they weren't aware that NSURLCache could be setup in two lines and do it 100× better. Even more developers have never known the benefits of network caching, and never attempted a solution, causing their apps to make untold numbers of unnecessary requests to the server.

So be the change you want to see in the world, and be sure to always start you app on the right foot, by setting a shared NSURLCache in -application:didFinishLaunchingWithOptions:.

ReactiveCocoa

$
0
0

Languages are living works. They are nudged and challenged and bastardized and mashed-up in a perpetual cycle of undirected and rapid evolution. Technologies evolve, requirements change, corporate stewards and open source community come and go; obscure dialects are vaulted to prominence on the shoulders of exciting new frameworks, and thrust into a surprising new context after a long period of dormancy.

Objective-C has a remarkable history spanning four acts in as many decades:

In its 1st act, Objective-C was adopted as the language of NeXT, powering NeXTSTEP and the world's first web server.

In its 2nd act, Objective-C positioned itself in the heart Apple's technology stack (after a prolonged turf war with Java) with Apple's acquisition of NeXT.

In its 3rd act, Objective-C rose to unprecedented significance with the release of iOS, making it the most important language of mobile computing.

Objective-C's 4th act takes us to the present day, with an influx of new iOS developers from the Ruby, Python, and Javascript communities sparking a revolution in open source participation. For the first time, Objective-C is being directly shaped and guided by the contributions of individuals outside of Apple.

Breaking from a tradition of covering Apple APIs exclusively, this edition of NSHipster will look at an open source project that exemplifies this brave new era for Objective-C: ReactiveCocoa.


For a complete look at ReactiveCocoa, refer to the project's README, Framework Overview and Design Guidelines.

ReactiveCocoa is an open source library that brings Functional Reactive Programming paradigm to Objective-C. It was created by Josh Abernathy& Justin Spahr-Summers in the development of GitHub for Mac. Last week, ReactiveCocoa reached a major milestone with its 1.0 release.

Functional Reactive Programming (FRP) is a way of thinking about software in terms of transforming inputs to produce output continuously over time. Josh Abernathy frames the paradigm thusly:

Programs take input and produce output. The output is the result of doing something with the input. Input, transform, output, done.

The input is all the sources of action for your app. It's taps. It's keyboard events. It's timer triggers, GPS events, and web service responses. These things are all inputs. They all feed into the app, and the app combines them all in some way to produce a result: the output.

The output is often a change in the app's UI. A switch is toggled or a list gets a new item. Or it could be more than that. It could be a new file on the device's disk, or it could be an API request. These things are the outputs of the app.

But unlike the classic input/output design, this input and output happens more than once. It's not just a single input → work → output—the cycle continues while the app is open. The app is always consuming inputs and producing outputs based on them.

To illustrate the difference between the conventional, imperative paradigm of Objective-C programming versus a functional reactive approach, consider the common example of validating a signup form:

Conventional

-(BOOL)isFormValid{return[self.usernameField.textlength]>0&&[self.emailField.textlength]>0&&[self.passwordField.textlength]>0&&[self.passwordField.textisEqual:self.passwordVerificationField.text];}#pragma mark - UITextFieldDelegate-(BOOL)textField:(UITextField*)textFieldshouldChangeCharactersInRange:(NSRange)rangereplacementString:(NSString*)string{self.createButton.enabled=[selfisFormValid];returnYES;}

In the conventional example, logic is fragmented across different methods in the view controller, with calls to self.createButton.enabled = [self isFormValid]; interspersed throughout delegate methods and view lifecycle callbacks.

Compare this with equivalent code using ReactiveCocoa:

ReactiveCocoa

RACSignal*formValid=[RACSignalcombineLatest:@[self.username.rac_textSignal,self.emailField.rac_textSignal,self.passwordField.rac_textSignal,self.passwordVerificationField.rac_textSignal]reduce:^(NSString*username,NSString*email,NSString*password,NSString*passwordVerification){return@([usernamelength]>0&&[emaillength]>0&&[passwordlength]>8&&[passwordisEqual:passwordVerification]);}];RAC(self.createButton.enabled)=formValid;

Here, all of the logic for validating form input is contained in a single chain of logic and responsibility. Each time any of the text fields is updated, their inputs are reduced into a single boolean value, which automatically enables / disables the create button.

Overview

ReactiveCocoa is comprised of two major components: signals (RACSignal) and sequences (RACSequence).

Both signals and sequences are kinds of streams, sharing many of the same operators. ReactiveCocoa has done well to abstract a wide scope of functionality into a semantically dense, consistent design: signals are a push-driven stream, and sequences are a pull-driven stream.

RACSignal

  • Handling Asynchronous Or Event-driven Data Sources: Much of Cocoa programming is focused on reacting to user events or changes in application state.
  • Chaining Dependent Operations: Dependencies are most often found in network requests, where a previous request to the server needs to complete before the next one can be constructed.
  • Parallelizing Independent Work: Working with independent data sets in parallel and then combining them into a final result is non-trivial in Cocoa, and often involves a lot of synchronization.

Signals send three different types of events to their subscribers:

  • The next event provides a new value from the stream. Unlike Cocoa collections, it is completely valid for a signal to include nil.
  • The error event indicates that an error occurred before the signal could finish. The event may include an NSError object that indicates what went wrong. Errors must be handled specially – they are not included in the stream's values.
  • The completed event indicates that the signal finished successfully, and that no more values will be added to the stream. Completion must be handled specially – it is not included in the stream of values.

The lifetime of a signal consists of any number of next events, followed by one error or completed event (but not both).

RACSequence

  • Simplifying Collection Transformations: Higher-order functions like map, filter, fold/reduce are sorely missing from Foundation.

Sequences are a kind of collection, similar in purpose to NSArray. Unlike an array, the values in a sequence are evaluated lazily (i.e., only when they are needed) by default, potentially improving performance if only part of a sequence is used. Just like Cocoa collections, sequences cannot contain nil.

RACSequence allows any Cocoa collection to be manipulated in a uniform and declarative way.

RACSequence*normalizedLongWords=[[words.rac_sequencefilter:^BOOL(NSString*word){return[wordlength]>=10;}]map:^(NSString*word){return[wordlowercaseString];}];

Precedents in Cocoa

Capturing and responding to changes has a long tradition in Cocoa, and ReactiveCocoa is a conceptual and functional extension of that. It is instructive to contrast RAC with those Cocoa technologies:

RAC vs. KVO

Key-Value Observing is at the heart of all magic in Cocoa—indeed, it is used extensively by ReactiveCocoa to react to property changes. However, KVO is neither pleasant nor easy to use: its API is overwrought with unused parameters and sorely lacking a blocks-based interface.

RAC vs. Bindings

Bindings are magic—voodoo, really.

Although essential to managing the complexity of a Mac OS X application, Bindings' cultural relevance has waned for years, as the focus has shifted to iOS and UIKit, which notably lacks support. Bindings replace a lot of boilerplate glue code and allow programming to be done in Interface Builder, but they're severely limited and impossible to debug. RAC offers a clear, understandable, and extensible code-based API that works in iOS and is apt to replace all but the most trivial uses of bindings in your OS X application.


Objective-C was built from Smalltalk's ideas on top of C's metal, but its cultural imports go far beyond its original pedigree.

@protocol was a rejection of C++'s multiple inheritance, favoring an abstract data type pattern comparable to a Java Interface. Objective-C 2.0 introduced @property / @synthesize, a contemporary of C#'s get; set; shorthand for getter and setter methods (as well as dot syntax, which is still a point of contention for NeXTSTEP hard-liners). Blocks injected some functional programming flavor to the language, which paired nicely with Grand Central Dispatch--a queue-based concurrency API almost certainly influenced by Fortran / C / C++ standard OpenMP. Subscripting and object literals, a standard feature in scripting languages like Ruby and Javascript, now finally brought to Objective-C thanks to a Clang language extension.

ReactiveCocoa brings a healthy dose of functional and reactive programming influence to Objective-C, and was itself influenced by C#'s Rx library, Clojure, and Elm.

Good ideas are contagious. ReactiveCocoa is a reminder that good ideas can come from unlikely places, and that a fresh perspective can make all of the difference with familiar problems.

NSAssertionHandler

$
0
0

"When at first you don't succeed, use an object-oriented injection point to override default exception handling." This is the sort of advice you would have learned at mother's knee if you were raised by NSAssertionHandler.

Programming incorporates numerous disciplines of human reasoning, from high-level discourse and semantics—the "story" we tell each other to explain how a system works—to the mathematical and philosophical machinery that underpins everything.

Assertions are a concept borrowed from classical logic. In logic, assertions are statements about propositions within a proof. In programming, assertions denote assumptions the programmer has made about the application at the place where they are declared.

When used in the capacity of preconditions and postconditions, which describe expectations about the state of the code at the beginning and end of execution of a method or function, assertions form a contract. Assertions can also be used to enforce conditions at run-time, in order to prevent execution when certain preconditions fail.

Assertions are similar to unit testing in that they define expectations about the way code will execute. Unlike unit tests, assertions exist inside the program itself, and are thereby constrained to the context of the program. Because unit tests are fully independent, they have a much greater capacity to isolate and test certain behaviors, using tools like methods stubs and mock objects. Developers should use assertions and unit tests in combination and in reasonable quantity to test and define behavior in an application.

Foundation Assertion Handling

Objective-C combines C-style assertion macros with an object-oriented approach to intercepting and handling assertion failures. Namely, NSAssertionHandler:

Each thread has its own assertion handler, which is an object of class NSAssertionHandler. When invoked, an assertion handler prints an error message that includes the method and class names (or the function name). It then raises an NSInternalInconsistencyException exception.

Foundation defines two pairs of assertion macros:

  • NSAssert / NSCAssert
  • NSParameterAssert / NSCParameterAssert

Foundation makes two distinctions in their assertion handler APIs that are both semantic and functional.

The first distinction is between a general assertion (NSAssert) and a parameter assertion (NSParameterAssert). As a rule of thumb, methods / functions should use NSParameterAssert / NSCParameterAssert statements at the top of methods to enforce any preconditions about the input values; in all other cases, use NSAssert / NSCAssert.

The second is the difference between C and Objective-C assertions: NSAssert should only be used in an Objective-C context (i.e. method implementations), whereas NSCAssert should only be used in a C context (i.e. functions).

  • When a condition in NSAssert or NSParameterAssert fails, -handleFailureInMethod:object:file:lineNumber:description: is called in the assertion handler.
  • When a condition in NSCAssert or NSCParameterAssert fails, -handleFailureInFunction:file:lineNumber:description: is called in the assertion handler.

Additionally, there are variations of NSAssert / NSCAssert, from NSAssert1 ... NSAssert5, which take their respective number of arguments to use in a printf-style format string.

Using NSAssertionHandler

It's important to note that as of Xcode 4.2, assertions are turned off by default for release builds, which is accomplished by defining the NS_BLOCK_ASSERTIONS macro. That is to say, when compiled for release, any calls to NSAssert& co. are effectively removed.

And while Foundation assertion macros are extremely useful in their own right—even when just used in development—the fun doesn't have to stop there. NSAssertionHandler provides a way to gracefully handle assertion failures in a way that preserves valuable real-world usage information.

That said, many seasoned Objective-C developers caution against actually using NSAssertionHandler in production applications. Foundation assertion handlers are something to understand and appreciate from a safe distance. Proceed with caution if you decide to use this in a shipping application.

NSAssertionHandler is a straightforward class, with two methods to implement in your subclass: -handleFailureInMethod:... (called on a failed NSAssert / NSParameterAssert) and -handleFailureInFunction:... (called on a failed NSCAssert / NSCParameterAssert).

LoggingAssertionHandler simply logs out the assertion failures, but those failures could also be logged to an external web service to be aggregated and analyzed, for example.

LoggingAssertionHandler.h

@interfaceLoggingAssertionHandler : NSAssertionHandler@end

LoggingAssertionHandler.m

@implementationLoggingAssertionHandler-(void)handleFailureInMethod:(SEL)selectorobject:(id)objectfile:(NSString*)fileNamelineNumber:(NSInteger)linedescription:(NSString*)format,...{NSLog(@"NSAssert Failure: Method %@ for object %@ in %@#%i",NSStringFromSelector(selector),object,fileName,line);}-(void)handleFailureInFunction:(NSString*)functionNamefile:(NSString*)fileNamelineNumber:(NSInteger)linedescription:(NSString*)format,...{NSLog(@"NSCAssert Failure: Function (%@) in %@#%i",functionName,fileName,line);}@end

Each thread has the option of specifying an assertion handler. To have the NSAssertionHandler subclass start handling failed assertions, set it as the value for the NSAssertionHandlerKey key in the thread's threadDictionary.

In most cases, it will make sense to set your assertion handler on the current thread inside -application: didFinishLaunchingWithOptions:.

AppDelegate.m

-(BOOL)application:(UIApplication*)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions{NSAssertionHandler*assertionHandler=[[LoggingAssertionHandleralloc]init];[[[NSThreadcurrentThread]threadDictionary]setValue:assertionHandlerforKey:NSAssertionHandlerKey];// ...returnYES;}

NSAssertionHandler reminds us of the best practices around articulating our expectations as programmers through assert statements.

But if we look deeper into NSAssertionHandler—and indeed, into our own hearts, there are lessons to be learned about our capacity for kindness and compassion; about our ability to forgive others, and to recover from our own missteps. We can't be right all of the time. We all make mistakes. By accepting limitations in ourselves and others, only then are we able to grow as individuals.

Or whatever.

Back Row

$
0
0

For years, many have predicted the announcement of an Apple TV SDK. We all know it's coming. It has to. And it will be amazing when it happens... whenever that is.

Everything is in place for Apple to kick-start the next generation of television, completely leap-frogging the current, pathetic crop of "smart TVs" like the iPhone did with its "smart phone" predecessors. All they need to do is open up the ecosystem.

But rather than simply wait for the future, we can take matters into our own hands, with class-dump and some reverse-engineering chutzpah.

Voila! A class dump of the Apple TV private framework headers

That's right: this edition of NSHipster covers a topic so obscure, it doesn't even officially exist.


Back Row is a private framework used in the Apple TV user experience. Its name is a reference to Front Row, an application included in Mac OS X 10.4 – 10.6 that paired with the Apple Remote to transform the Mac into a couch-friendly media center.

The original Apple TV could be described as a "short Mac Mini", which ran a modified version of Front Row on a stripped-down build of Mac OS X. It was little more than an iTunes remote, streaming content from a shared iTunes library on a separate computer.

The second generation of the device took a smaller form factor, shifting its focus from media storage and management to on-demand streaming. The second generation Apple TV user interface reflected this in both its design and implementation. BackRow was ported from OS X to iOS, as it transcended its original role coordinating iTunes libraries to become an extensible platform for streaming media appliances.

Back Row & UIKit

Back Row (name prefix: BR) bears a striking resemblance to UIKit, with many of the familiar metaphors and conventions of iOS development.

Here's a brief list of some Back Row classes & protocols and their UIKit equivalents:

Back RowUIKit
<BRResponder><UIResponder>
<BRAppliance><UIApplication>
BRControllerUIViewController
BRMenuControllerUITableViewController
BRControllerStackUINavigationController
BRGridViewUICollectionView
BRListViewUITableView

Apple TV Appliance Structure

Apple TV Home Screen

In the current Apple TV interface, the home screen contains a grid of rectangular icons, similar to the home screen on iOS. Each icon corresponds to an appliance.

Why an appliance and not an application? An appliance is more limited in what it can do as compared to an application. On iPhone or iPad, applications range from social media clients and photo tools to games and musical instruments. Whereas on Apple TV, an appliance consists of a series of remote-friendly menus, lists, and grids, which ultimately lead to media playback of some form. When it comes to appliances, (audio / video) content is king.

When an appliance launches, it displays a list of BRApplianceCategory items. Each category has its own name, identifier, and preferred ordering. When a category is selected, the appliance calls - controllerForIdentifier:args:, which returns a BRController object.

An appliance also has an optional topShelfController, which is what displays at the top of the home screen when the app is highlighted.

Pushing and popping controllers is managed by a shared BRControllerStack. When a controller is selected with in a list, it is pushed onto the stack. When the user presses the Menu button, the stack is popped.

Apple TV YouTube

A typical controller consists of a menu list on the right, with some kind of complimentary view on the left.

On top-level controllers, this sometimes takes the form of a BRMarqueeStack, which animates a Cover-Flow-style sequence of preview images for each of the controllers.

For controllers listing media that can be played, the complimentary view usually shows a preview image, along with meta data in a BRMetadataControl, such as runtime, date created, and other relevant information.

Apple TV Movie

iTunes store controllers also use a horizontally-stacked layout, with media information at the top, with related titles listed below.

Points of Interest

Diving into the class dump of the Apple TV frameworks reveals a treasure trove of interesting tidbits. With only undocumented header files to go by, there's still a lot of mystery to what all's in these private frameworks, or how they fit together. However a thoughtful analysis of class and method names offers some workable clues into their inter-workings.

Here are some of the more interesting parts of the Back Row framework headers (again, all of this is complete speculation):

  • BRURLImageProxy: A protocol that encapsulates the process of loading and displaying images at various dimensions.
  • BRKeyboard: It's always fascinating to see how Apple architects controls. Keyboards populate and manage interactions with the grid view of character and action keys, and are divided into classes for Roman and Japanese scripts.
  • BRStateMachine: No other Apple frameworks expose a class for state machines. LATVLeaseAgent is a subclass in the AppleTV framework that appears to negotiate the terms of iTunes movie rentals.
  • BRMappingDictionary: A new and useful-looking collection class that functions as an NSMutableDictionary, but also allows for an NSValueTransformer to be set for each key (-transformedValueForKey:forObject: in addition to -valueForKey:)
  • BRMerchant: What you might expect in terms of a class representing a store client, with some interesting class methods. itms is in reference to the iTunes Music Store, but what's sedona and flagstaff? They're probably codewords for streaming services that fall under the umbrella of the iTunes store.
  • <BRControlFactory><BRMetadataPopulator>& BRControlMediator: Factories, Populators, and Mediators are not commonly seen design patterns in Apple frameworks, although they are described in the Cocoa Fundamentals Guide.

Building Your Own Apple TV App

In the immortal words of Jeff Goldblum: "Life finds a way".

Undeterred by the litigious shadow of Apple Inc., nor the undocumented wilds of a private API, a cadre of jail-breaking homesteaders have cracked the nut on Apple TV development with promising results.

One of the most polished among them is UitzendingGemist led by none other than Eloy Durán of CocoaPods fame, along with Kevin Bradley and Michael Gile.

As you can see from this video of an early version, you can run your very own applications on a jail-broken Apple TV (OS 5.0.1 or compatible). The code is relatively straightforward, fetching a catalog of media files from the Dutch public broadcasting site UitzendingGemist.nl, and playing them on demand.


It's hard to say what it will take for Apple to open up the Apple TV ecosystem. Is it a matter of getting the APIs documented and ready for public use? Is there a process underway to refactor Back Row into UIKit? Or is everything pretty much ready, and it's just a matter of other business pieces falling into place?

Only time will tell.

In the meantime, you can get a head-start on what will almost certainly be a gold-rush on the scale of the first generation of iPhone apps.

UIAppearance

$
0
0

Style vs. Substance.
Message vs. Medium.
Rhetoric vs. Dialectic.

Is beauty merely skin deep, or is it somehow informed by deeper truths?
What does it mean for something to possess good design?
Are aesthetic judgments relative, or absolute?

These are deep questions that have been pondered by philosophers, artists, and makers alike for millenia.

And while we all continue our search for beauty and understanding in the universe, the app marketplace has been rather clear on this subject:

Users will pay a premium for good-looking software.

When someone purchases an iPhone, they are buying into Apple's philosophy that things that work well should look good, too. The same goes for when we choose to develop for iOS—a sloppy UI reflects poorly on the underlying code.

It used to be that even trivial UI customization on iOS required AppStore-approval-process-taunting ju-ju like method swizzling. Fortunately, with iOS 5, developers were given an easier way: UIAppearance.


UIAppearance allows the appearance of views and controls to be consistently defined across the entire application.

In order to have this work within the existing structure of UIKit, Apple devised a rather clever solution: UIAppearance is a protocol that returns a proxy that will forward any configuration to instances of a particular class. Why a proxy instead of a property or method on UIView directly? Because there are non-UIView objects like UIBarButtonItem that render their own composite views. Appearance can be customized for all instances, or scoped to particular view hierarchies:

  • +appearance: Returns the appearance proxy for the receiver.
  • +appearanceWhenContainedIn:(Class <UIAppearanceContainer>)ContainerClass,...: Returns the appearance proxy for the receiver in a given containment hierarchy.

To customize the appearance of all instances of a class, you use appearance to get the appearance proxy for the class. For example, to modify the tint color for all instances of UINavigationBar:

[[UINavigationBarappearance]setTintColor:myColor];

To customize the appearances for instances of a class when contained within an instance of a container class, or instances in a hierarchy, you use appearanceWhenContainedIn: to get the appearance proxy for the class:

[[UIBarButtonItemappearanceWhenContainedIn:[UINavigationBarclass],nil]setTintColor:myNavBarColor];[[UIBarButtonItemappearanceWhenContainedIn:[UINavigationBarclass],[UIPopoverControllerclass],nil]setTintColor:myPopoverNavBarColor];[[UIBarButtonItemappearanceWhenContainedIn:[UIToolbarclass],nil]setTintColor:myToolbarColor];[[UIBarButtonItemappearanceWhenContainedIn:[UIToolbarclass],[UIPopoverControllerclass],nil]setTintColor:myPopoverToolbarColor];

Determining Which Properties Work With UIAppearance

One major downside to UIAppearance's proxy approach is that it's difficult to know which selectors are compatible. Because +appearance returns an id, Xcode can't provide any code-completion information. This is a major source of confusion and frustration with this feature.

In order to find out what methods work with UIAppearance, you have to look at the headers:

$ cd /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/
  Developer/SDKs/iPhoneOS*.sdk/System/Library/Frameworks/UIKit.framework/Headers
$ grep -H UI_APPEARANCE_SELECTOR ./* | sed 's/ __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0) UI_APPEARANCE_SELECTOR;//'

UIAppearance looks for the UI_APPEARANCE_SELECTOR macro in method signatures. Any method with this annotation can be used with the appearance proxy.

For your convenience, here is the list of properties as of iOS 6.1

Implementing <UIAppearance> in Custom UIView Subclasses

Much like how NSLocalizedString and #pragma are marks of quality in Objective-C code, having custom UI classes conform to UIAppearance is not only a best-practice, but it demonstrates a certain level of care being put into its implementation.

Peter Steinberger has this great article, which describes some of the caveats about implementing UIAppearance in custom views. It's a must-read for anyone who aspires to greatness in their open source UI components.

Alternatives

Another major shortcoming of UIAppearance is that style rules are imperative, rather than declarative. That is, styling is applied at runtime in code, rather than being interpreted from a list of style rules.

Yes, if there's one idea to steal from web development, it's the separation of content and presentation. Say what you will about CSS, but stylesheets are amazing.

Stylesheet enthusiasts on iOS now have some options. Pixate is a commercial framework that uses CSS to style applications. NUI, an open-source project by Tom Benner, does much the same with a CSS/SCSS-like language. Another open source project along the same lines is UISS by Robert Wijas, which allows UIAppearance rules to be read from JSON.


Cocoa developers have a long history of obsessing about visual aesthetics, and have often gone to extreme ends to achieve their desired effects. Recall the Delicious Generation of Mac developers, and applications like Disco, which went so far as to emit virtual smoke when burning a disc.

This spirit of dedication to making things look good is alive and well in iOS. As a community and as an ecosystem, we have relentlessly pushed the envelope in terms of what users should expect from their apps. And though this makes our jobs more challenging, it makes the experience of developing for iOS all the more enjoyable.

Settle for nothing less than the whole package.
Make your apps beautiful from interface to implementation.

C Storage Classes

$
0
0

It's time, once again, to take a few steps back from the world of Objective-C, and look at some underlying C language features. Hold onto your fedoras, ladies & gents, as we dive into C storage classes in this week's edition of NSHipster.


In C, the scope and lifetime of a variable or function within a program is determined by its storage class. Each variable has a lifetime, or the context in which they store their value. Functions, along with variables, also exist within a particular scope, or visibility, which dictates which parts of a program know about and can access them.

There are 4 storage classes in C:

  • auto
  • register
  • static
  • extern

At least a few of these will look familiar to anyone who has done a cursory amount of Objective-C programming. Let's go into more detail with each one:

auto

There's a good chance you've never seen this keyword in the wild. That's because auto is the default storage class, and therefore doesn't need to be explicitly used often.

Automatic variables have memory automatically allocated when a program enters a block, and released when the program leaves that block. Access to automatic variables is limited to only the block in which they are declared, as well as any nested blocks.

register

Most Objective-C programmers probably aren't familiar with register either, as it's just not widely used in the NS world.

register behaves just like auto, except that instead of being allocated onto the stack, they are stored in a register.

Registers offer faster access than RAM, but because of the complexities of memory management, putting variables in registers does not guarantee a faster program—in fact, it may very well end up slowing down execution by taking up space on the register unnecessarily. As it were, using register is actually just a suggestion to the compiler to store the variable in the register; implementations may choose whether or not to honor this.

register's lack of popularity in Objective-C is instructive: it's probably best not to bother with it, as it's much more likely to cause a headache than speed up your app in any noticeable way.

static

Finally, one that everyone's sure to recognize: static.

As a keyword, static gets used in a lot of different, incompatible ways, so it can be confusing to figure out exactly what it means in every instance. When it comes to storage classes, static means one of two things.

  1. A static variable inside a method or function retains its value between invocations.
  2. A static variable declared globally can called by any function or method, so long as those functions appear in the same file as the static variable. The same goes for static functions.

Static Singletons

A common pattern in Objective-C is the static singleton, wherein a statically-declared variable is initialized and returned in either a function or class method. dispatch once is used to guarantee that the variable is initialized exactly once in a thread-safe manner:

+(instancetype)sharedInstance{staticid_sharedInstance=nil;staticdispatch_once_tonceToken;dispatch_once(&onceToken,^{_sharedInstance=[[selfalloc]init];});return_sharedInstance;}

The singleton pattern is useful for creating objects that are shared across the entire application, such as an HTTP client or a notification manager, or objects that may be expensive to create, such as formatters.

extern

Whereas static makes functions and variables globally visible within a particular file, extern makes them visible globally to all files.

Global variables are not a great idea, generally speaking. Having no constraints on how or when state can be mutated is just asking for impossible-to-debug bugs. That said, there are two common and practical uses for extern in Objective-C.

Global String Constants

Any time your application uses a string constant with a non-linguistic value in a public interface, it should declare it as an external string constant. This is especially true of keys in userInfo dictionaries, NSNotification names, and NSError domains.

The pattern is to declare an externNSString * const in a public header, and define that NSString * const in the implementation:

AppDelegate.h

externNSString*constkAppErrorDomain;

AppDelegate.m

NSString*constkAppErrorDomain=@"com.example.yourapp.error";

It doesn't particularly matter what the value of the string is, so long as it's unique. Using a string constant establishes a strict contract, that the constant variable is used instead of the string's literal value itself.

Public Functions

Some APIs may wish to expose helper functions publicly. For auxiliary concerns and state-agnostic procedures, functions are a great way to encapsulate these behaviors—and if they're particularly useful, it may be worth making them available globally.

The pattern follows the same as in the previous example:

TransactionStateMachine.h

typedefNS_ENUM(NSUInteger,TransactionState){TransactionOpened,TransactionPending,TransactionClosed,};externNSString*NSStringFromTransactionState(TransactionStatestate);

TransactionStateMachine.m

NSString*NSStringFromTransactionState(TransactionStatestate){switch(state){caseTransactionOpened:
      return@"Opened"caseTransactionPending:
      return@"Pending";caseTransactionClosed:
      return@"Closed";default:returnnil;}}

To understand anything is to make sense of its context. What we may see as obvious and self-evident, is all but unknown to someone without our frame of reference. Our inability to truly understand or appreciate the differences in perspective and information between ourselves and others is perhaps our most basic shortcoming.

That is why, in our constructed logical universe of 0's and 1's, we take such care to separate contexts, and structure our assumptions based on these explicit rules. C storage classes are essential to understanding how a program operates. Without them, we are left to develop as one might walk on egg shells. So take heed of these simple rules of engagement and go forth to code with confidence.


Search Kit

$
0
0

NSHipsters love irony, right? How about this for irony:

There's this framework called Search Kit, which despite being insanely powerful and useful for finding information, is something that almost no one has ever heard of.

It's true! I'd reckon there's a better chance that you have implemented your own search functionality from scratch than have ever even heard of Search Kit. (Heck, most people haven't even heard of Core Services, its parent framework)

If only everyone knew that they could harness the same killer search functionality that Apple uses for their own applications...


Search Kit is a C framework for searching and indexing content in human languages. It supports matching on phrase or partial word, including logical (AND, OR) and wildcard (*) operators, and can rank results by relevance. Search Kit also provides document summarization, which is useful for generating representative excerpts. And best of all: it's thread-safe.

All of the whiz-bang search-as-you-type features in Mac OS X—from Mail.app and Xcode to System Preferences and Spotlight—use Search Kit under the hood.

But to understand how Search Kit does its magic, it's important to explain some of the basics of Information Retrieval and Natural Language Processing.

Be sure to check out Apple's Search Kit Programming Guide for an authoritative explanation of the what's, why's, and how's of this great framework.

Search 101

Quoth Apple:

You have an information need. But before you can ask a question, you need someone or something to ask. That is, you need to establish who or what you will accept as an authority for an answer. So before you ask a question you need to define the target of your question.

Finding the answer in a reasonable amount of time requires effort from the start. This is what that process looks like in general terms:

Extract

First, content must be extracted from a corpus. For a text document, this could involve removing any styling, formatting, or other meta-information. For a data record, such as an NSManagedObject, this means taking all of the salient fields and combining it into a representation.

Once extracted, the content is tokenized for further processing.

Filter

In order to get the most relevant matches, it's important to filter out common, or "stop" words like articles, pronouns, and helping verbs, that don't really contribute to overall meaning.

Reduce

Along the same lines, words that mean basically the same thing should be reduced down into a common form. Morpheme clusters, such as grammatical conjugations like "computer", "computers", "computed", and "computing", for example, can all be simplified to be just "compute", using a stemmer. Synonyms, likewise, can be lumped into a common entry using a thesaurus lookup.

Index

The end result of extracting, filtering, and reducing content into an array of normalized tokens is to form an inverted index, such that each token points to its origin in the index.

After repeating this process for each document or record in the corpus until, each token can point to many different articles. In the process of searching, a query is mapped onto one or many of these tokens, retrieving the union of the articles associated with each token.

Using Search Kit

Creating an Index

SKIndexRef is the central data type in Search Kit, containing all of the information needed to process and fulfill searches, and add information from new documents. Indexes can be persistent / file-based or ephemeral / in-memory. Indexes can either be created from scratch, or loaded from an existing file or data object—and once an index is finished being used, like many other C APIs, the index is closed.

Adding Documents to an Index

SKDocumentRef is the data type associated with entries in the index. When a search is performed, documents (along with their context and relevance) are the results.

Each SKDocumentRef is associated with a URI.

For documents on the file system, the URI is simply the location of the file on disk:

NSURL*fileURL=[NSURLfileURLWithPath:@"/path/to/document"];SKDocumentRefdocument=SKDocumentCreateWithURL((__bridgeCFURLRef)fileURL);

For Core Data managed objects, the NSManagedObjectID -URIRepresentation can be used:

NSURL*objectURL=[objectIDURIRepresentation];SKDocumentRefdocument=SKDocumentCreateWithURL((__bridgeCFURLRef)objectURL);

For any other kinds of data, it would be up to the developer to define a URI representation.

When adding the contents of a SKDocumentRef to an SKIndexRef, the text can either be specified manually:

NSString*string=@"Lorem ipsum dolar sit amet"SKIndexAddDocumentWithText(index,document,(__bridgeCFStringRef)string,true);

...or collected automatically from a file:

NSString*mimeTypeHint=@"text/rtf"SKIndexAddDocument(index,document,(__bridgeCFStringRef)mimeTypeHint,true);

To change the way a file-based document's contents are processed, properties can be defined when creating the index:

NSSet*stopwords=[NSSetsetWithObjects:@"all",@"and",@"its",@"it's",@"the",nil];NSDictionary*properties=@{@"kSKStartTermChars":@"",// additional starting-characters for terms@"kSKTermChars":@"-_@.'",// additional characters within terms@"kSKEndTermChars":@"",// additional ending-characters for terms@"kSKMinTermLength":@(3),@"kSKStopWords":stopwords};SKIndexRefindex=SKIndexCreateWithURL((CFURLRef)url,NULL,kSKIndexInverted,(CFDictionaryRef)properties);

Searching

SKSearchRef is the data type constructed to perform a search on an SKIndexRef. It contains a reference to the index, a query string, and a set of options:

NSString*query=@"kind of blue";SKSearchOptionsoptions=kSKSearchOptionDefault;SKSearchRefsearch=SKSearchCreate(index,(CFStringRef)query,options);

SKSearchOptions is a bitmask with the following possible values:

  • kSKSearchOptionDefault: Default search options include:
    • Relevance scores will be computed
    • Spaces in a query are interpreted as Boolean AND operators.
    • Do not use similarity searching.

These options can be specified individually as well:

  • kSKSearchOptionNoRelevanceScores: This option saves time during a search by suppressing the computation of relevance scores.
  • kSKSearchOptionSpaceMeansOR: This option alters query behavior so that spaces are interpreted as Boolean OR operators.
  • kSKSearchOptionFindSimilar: This option alters query behavior so that Search Kit returns references to documents that are similar to an example text string. When this option is specified, Search Kit ignores all query operators.

Putting this all together is SKIndexCopyDocumentURLsForDocumentIDs, which performs the search and fills arrays with the results. Iterating through the range of found matches provides access to the document URL and relevance score (if calculated):

NSUIntegerlimit=...;// Maximum number of resultsNSTimeIntervaltime=...;// Maximum time to get results, in secondsSKDocumentIDdocumentIDs[limit];CFURLRefurls[limit];floatscores[limit];CFIndexcount;BooleanhasResult=SKSearchFindMatches(search,limit,documentIDs,scores,time,&count);SKIndexCopyDocumentURLsForDocumentIDs(index,foundCount,documentIDs,urls);NSMutableArray*mutableResults=[NSMutableArrayarray];[[NSIndexSetindexSetWithIndexesInRange:NSMakeRange(0,count)]enumerateIndexesUsingBlock:^(NSUIntegeridx,BOOL*stop){CFURLRefurl=urls[idx];floatrelevance=scores[idx];NSLog(@"- %@: %f",url,relevance);if(objectID){[mutableResultsaddObject:(NSURL*)url];}CFRelease(url);}];

For more examples of Search Kit in action, be sure to check out Indragie Karunaratne's project, SNRSearchIndex.


And so this article becomes yet another document in the corpus we call the Internet. By pointing to Search Kit, and explaining even the briefest of its features, this—the strings of tokens you read at this very moment—are (perhaps) making it easier for others to find Search Kit.

...and it's a good thing, too, because Search Kit is a wonderful and all-too-obscure framework, which anyone building a content-based system would do well to investigate.

iCloud

$
0
0

The Lisa. The Twentieth Anniversary Macintosh. The iPod Hi-Fi. The MacBook Wheel.

Each of these products exemplifies Apple's obsessive pursuit of quality as much as its unrivaled ability to anticipate the direction of things to come and execute flawlessly.

In the words of Wayne Gretzky: Skate where the puck's going, not where it's been.

But perhaps what Apple is most renowned for, however, is its consistent track record for creating great webservices. From consumer products like MobileMe and Ping to developer tools including the Provisioning Portal and iTunes Connect, Apple has continued to set new standards for convenience, robustness, and extensibility.

So when Apple introduced iCloud at WWDC in 2011, everyone in the audience was rapt in anticipation, overcome with a sense of optimistic wonder. "Not again!", we said to ourselves, shaking our head with a knowing smile. "This changes everything!"

And indeed, iCloud has changed everything. Although it seemed almost too good to be true when Steve Jobs got up on that stage in Moscone to announce iCloud to the world that morning in June—if anything, Apple has under-promised and over-delivered with iCloud.

Now, NSHipster usually covers obscure topics that you've probably never heard of. But this is one of those days where it just feels right to take this opportunity today to make sure we're all on the same page about iCloud.


iCloud is an umbrella term for the latest evolution of Apple's consumer webservices. Following from the success of iTools, .Mac, and MobileMe, iCloud manages our digital lives like never before, with features like Photo Stream, iTunes Match, and Documents in the Cloud.

What really ties everything together are the iCloud Storage APIs that allow developers to easily create applications to stay connected across all of your devices. These APIs come in three different flavors, depending on the particular needs of your application:

  • Key-value storage for discrete values, such as preferences, settings, and simple app state.
  • Document storage for user-visible file-based information such as word processing documents, drawings, and complex app state.
  • Core Data storage for shoebox-style apps and server-based, multi-device database solutions for structured content. iCloud Core Data storage is built on document storage and employs the same iCloud APIs.

Key-Value Storage... in the Cloud!

To store discrete values in iCloud for app preferences, app configuration, or app state, use iCloud key-value storage. Key-value storage is similar to the local user defaults database; but values that you place in key-value storage are available to every instance of your app on all of a user’s various devices.

Everyone knows that key-value storage is the secret to achieving Web Scale. That's just science.

Inject a healthy dose of Web Scale convenience into your app by incorporating NSUbiquitousKeyValueStore into your app:

-(BOOL)application:(UIApplication*)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions{[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(ubiquitousKeyValueStoreDidChange:)name:NSUbiquitousKeyValueStoreDidChangeExternallyNotificationobject:[NSUbiquitousKeyValueStoredefaultStore]];[[NSUbiquitousKeyValueStoredefaultStore]synchronize];returnYES;}

Document Storage... in the Cloud!

Adopting iCloud document storage makes your app’s documents available on all of a user’s devices. Documents automatically implement most of the behavior expected of iCloud apps. Specifically, a document automatically ensures that local changes are safely coordinated with iCloud-originated changes.

Leave filesystem-based storage to those poor terrestrial bound souls who haven't been raptured to the iCloud. Dropbox? Never heard of 'em.

Having documents reside entirely in application-specific cloud containers means less clutter in your digital life. Why should other applications be able to access documents anyway? Why would I want to use any more than a single app for any particular task?

They say seeing is believing, but iCloud is built on faith—that everything will be there next time you open Pages, Keynote, or TextEdit. Leave the Finder to play with its folders and .DS_Store files; we shall inherit the open skies of digital freedom.

Core Data Storage... in the Cloud!

Adopting iCloud Core Data storage makes the content in a shoebox-style app (like iPhoto) or a database-style app (like Bento) available on all of a user’s devices. Each instance of your app, on each device attached to an iCloud account, maintains its own local Core Data store file. When data changes locally, Core Data writes change log files to your app’s default ubiquity container.

Developers really love Core Data syncing over iCloud. Seriously, they just can'tstopravingaboutit.

Just when you thought Core Data couldn't get simpler, iCloud once again redefines our expectations.

Every time your application receives a NSPersistentStoreDidImportUbiquitousContentChangesNotification is reminiscent of that excitement of seeing the FedEx truck pull up with your pre-ordered iPhone 5. "This is the first day of the rest of my life", you'll think to yourself as you sign the proverbial confirmation slip of the package.

Sure, there's a chance that what you're signing is actually a repossession confirmation, and that the delivery guy will proceed to bust into your apartment and take everything you once owned, but at least you still have your new iPhone.

So it goes. Even an enlightened iLife is not without its risks.


Life just seems to float by, now that iCloud is managing our digital existence. No longer do we have to think about whether we have all of the information we need to go about our day:

From the moment our iPhone wakes us up with the "Marimba" ringtone, to our daily commute with Siri talking us through our day, and a productive work day using iWork; from the walk to the gym, listening to Podcasts.app, and working out with iTunes Sync, until our last waking hours as we wind down the day with Game Center, Apple and iCloud makes every day special.

And with the iCloud Storage APIs, you too can add your application to that perfect routine of digitally-synced bliss.

No foolin'.

BOOL / bool / Boolean / NSCFBoolean

$
0
0

We've talked before about the philosophical and technical concerns of nothingness in programming. This week, our attention turns to another fundamental matter: Truth.

Truth. Vēritās. The entire charter of Philosophy is founded upon the pursuit of it, and yet its exact meaning and implications still elude us. Does truth exist independently, or is it defined contingently against falsity? Can a proposition be at once both true and false? Is there absolute truth in anything, or is everything relative?

Once again, encoding our logical universe into the cold, calculating bytecode of computers forces us to deal with these questions one way or another. And as you'll see from our discussion of boolean types in Objective-C and its kin, truth is indeed stranger than fiction.


Objective-C defines BOOL to encode truth value. It is a typedef of a signed char, with the macros YES and NO to represent true and false, respectively.

Boolean values are used in conditionals, such as if or while statements, to conditionally perform logic or repeat execution. When evaluating a conditional statement, the value 0 is considered "false", while any other value is considered "true". Because NULL and nil are defined as 0, conditional statements on these nonexistent values are also evaluated as "false".

In Objective-C, use the BOOL type for parameters, properties, and instance variables dealing with truth values. When assigning literal values, use the YES and NO macros.

The Wrong Answer to the Wrong Question

Novice programmers often include an equality operator when evaluating conditionals:

if([aisEqual:b]==YES){...}

Not only is this unnecessary, but depending on the left-hand value, it may also cause unexpected results, as described in the Big Nerd Ranch blog post, "BOOL's Sharp Edges":

staticBOOLdifferent(inta,intb){returna-b;}

An overly clever C programmer might take some satisfaction in the simplicity of this approach: indeed, two integers are equal if and only if their difference is 0.

However, because of the reality of BOOL being typedef'd as a signed char, this will not behave as expected:

if(different(11,10)==YES){printf("11 != 10\n");}else{printf("11 == 10\n");}if(different(10,11)==YES){printf("10 != 11\n");}else{printf("10 == 11\n");}if(different(512,256)==YES){printf("512 != 256\n");}else{printf("512 == 256\n");}

This evaluates to:

11 != 10
10 == 11
512 == 256

Now, this might be acceptable for JavaScript, but Objective-C don't suffer fools gladly.

Deriving truth value directly from an arithmetic operation is never a good idea. Like the sentence "Colorless green ideas sleep furiously", it may be grammatical (after all, BOOL is a signed char like any other, so it could be treated as a number), but it doesn't make sense semantically. Instead, use the result of the == operator, or cast values into booleans with the ! (or !!) operator.

The Truth About NSNumber and BOOL

Pop quiz: what is the output of the following expression?

NSLog(@"%@",[@(YES)class]);

The answer:

__NSCFBoolean

Wait, what?

All this time, we've been led to believe that NSNumberboxes primitives into an object representation. Any other integer- or float-derived NSNumber object shows its class to be __NSCFNumber. What gives?

NSCFBoolean is a private class in the NSNumberclass cluster. It is a bridge to the CFBooleanRef type, which is used to wrap boolean values for Core Foundation property lists and collections. CFBoolean defines the constants kCFBooleanTrue and kCFBooleanFalse. Because CFNumberRef and CFBooleanRef are different types in Core Foundation, it makes sense that they are represented by different bridging classes in NSNumber.

For most people, boolean values and boxed objects "just work", and don't really care what goes into making the sausage. But here at NSHipster, we're all about sausages.


So, to recap, here is a table of all of the truth types and values in Objective-C:

NameTypedefHeaderTrue ValueFalse Value
BOOLsigned charobjc.hYESNO
bool_Bool (int)stdbool.htruefalse
Booleanunsigned charMacTypes.hTRUEFALSE
NSNumber__NSCFBooleanFoundation.h@(YES)@(NO)
CFBooleanRefstructCoreFoundation.hkCFBooleanTruekCFBooleanFalse

NSSecureCoding

$
0
0

A short post for this week: everything you need to know about NSSecureCoding.


NSSecureCoding is a protocol introduced in the iOS 6 / Mac OS X 10.8 SDKs. Aside from a few mentions at WWDC, NSSecureCoding remains relatively obscure—most developers have perhaps heard of it, but perhaps never went so far as to look up what it does.

NSSecureCoding extends the NSCoding protocol by adding the class method:

+(BOOL)supportsSecureCoding;

By conforming to NSSecureCoding and returning YES for +supportsSecureCoding, a class declares that it handles encoding and decoding of instances of itself in a way that guards against substitution attacks.

Specifically, classes that override -initWithCoder and conform to NSSecureCoding should use -decodeObjectOfClass:forKey: rather than -decodeObjectForKey:.

Why is this important? Recall that NSCoding is Foundation's way of marshaling objects to be either archived on a file system, or copied to another address space. When -decodeObjectForKey: is used to decode representations of objects into actual objects, there is no guarantee that the result of creating the object will be what was expected. If that representation is corrupted—specifically, in changing the target class (and thus designated initializer)—the application runs the risk of constructing unknown objects. Whether by malicious intent or an incidental coding error, this can cause serious problems.

It's not an apples-to-apples comparison, but it's somewhat similar to recent YAML exploit found in Rails.

For an XPC service, which is designed with security in mind, data integrity of this nature is especially important. It's a safe bet that XPC will only wax influence in subsequent iOS and OS X releases, so it's good to keep this all in mind.

Anyway, NSSecureCoding patches this vulnerability by establishing a contract for best practices. Now, decoding an object requires the class to be known ahead of time.

Whereas a standard, secure implementation of -initWithCoder: might have a check like:

idobj=[decoderdecodeObjectForKey:@"myKey"];if(![objisKindOfClass:[MyClassclass]]){// fail}

...an NSSecureCoding-conforming class would use:

idobj=[decoderdecodeObjectOfClass:[MyClassclass]forKey:@"myKey"];

Sometimes, a little API change makes all of the difference.


So now you know what's up with NSSecureCoding. Keep an eye out for that going forward: XPC is only going to become more important. Perhaps not today, perhaps not tomorrow, but someday—you will probably need to implement NSSecureCoding. And when that day comes... you'll be ready.

Stay safe, everyone.

NSHipster Quiz #1

$
0
0

On April 9th, the first-ever NSHipster Pub Quiz was held in Berlin. Think of your traditional pub quiz crossed with "Stump the Experts", with questions about things that you know and care about: computers, programming, Apple trivia—that sort of thing. The event was hosted by UIKonf, and made possible by its organizers Chris Eidhof, Matt Patterson, and Peter Bihr. Thanks again to Chris, Matt, and Peter, and everyone who came out to make it such an amazing event.

All told, a whopping 50-some folks came out, composing a dozen or so teams of up to 6 people, with names such as "NSBeep", "alloc] win_it]", & "- Bug Fixes / - Performance Improvements". At the end of the evening, it was the CodeKollectiv team that claimed top prize, with a score of 30pts.

Here are the rules to play along at home:

  • There are 4 Rounds, with 10 questions each
  • Record answers on a separate sheet of paper
  • Each correct answer to a question gets you 1 point
  • Play with up to 5 friends for maximum enjoyment
  • Don't be lame and look things up on the internet or in Xcode

Round 1: General Knowledge

  1. What does NS stand for?
  2. When Steve Jobs introduced the iPhone, he made a prank call to Starbucks. How many lattés did he order to-go? a. 3000 b. 4000 c. 6000
  3. NSOperation has 4 properties used as keypaths for operation object states. What are they?
  4. On your answer sheet, draw a UITableViewCell with UITableViewCellStyleValue2.
  5. Which UIKit protocol contains the method –tableView:heightForRowAtIndexPath:?
  6. What is the storage type of BOOL? (i.e. typedef equivalent)
  7. When was the Unix Epoch? Hint: NSDate has an initializer referencing this.
  8. What is the current version of Xcode?
  9. What was the first article written on NSHipster?
  10. How many apps were on on the home screen of the first iPhone?

Round 2: APIs

You will be given the name of the class, and the description of the property or method from the documentation. You need to tell me the name of that method or property.

  1. UIView: "A flag used to determine how a view lays out its content when its bounds change."
  2. UIAccessibility: "A brief description of the result of performing an action on the accessibility element, in a localized string."
  3. UIColor: "Returns a color object whose RGB values are 0.0, 1.0, and 1.0 and whose alpha value is 1.0."
  4. UIAlertView: "Sent to the delegate when the user clicks a button on an alert view."
  5. UIButton: "A Boolean value that determines whether tapping the button causes it to glow."
  6. UITableView: "Reloads the specified rows using a certain animation effect."
  7. UITableViewDataSource: "Tells the data source to return the number of rows in a given section of a table view."
  8. UIWebView: "Sets the main page content and base URL."
  9. UIGestureRecognizer: "Sent to the receiver when one or more fingers touch down in the associated view."
  10. UIDictationPhrase: "The most likely textual interpretation of a dictated phrase."

Round 3: Picture Round

  • 1. What is this?

Question 1

  • 2. What is this?

Question 2

  • 3. What is this?

Question 3

  • 4. What is this?

Question 4

  • 5. WTF is this?

Question 5

  • 6. Who is this?

Question 6

  • 7. Who is this?

Question 7

  • 8. Who is this?

Question 8

  • 9. Who is this?

Question 9

  • 10. In this photo, Bill Gates & Steve Jobs are being interviewed at the D5 conference in 2007 by a man and a woman just off-screen to the left. Who are they? (One point for each person)

Question 10

Round 4: Name That Framework!

For each question, a list of three classes from the same framework have been listed without their two-letter namespace prefix. Name the framework that they all belong to!

  1. Color List, Matrix, Sound
  2. Composition, URL Asset, Capture Session
  3. Enclosure, Author, Feed
  4. Geocoder, Location, Region
  5. Merge Policy, Mapping Model, Incremental Store
  6. Analysis, Summary, Search
  7. Record, Person, MultiValue
  8. View, View Controller, Skybox Effect
  9. Central Manager, Descriptor, Peripheral Delegate
  10. Filter, Face Feature, Vector

Answers

Round 1: General Knowledge

  1. NeXTSTEP
  2. 4000
  3. isReady, isExecuting, isFinished, isCancelled
  4. textLabel detailTextLabel
  5. UITableViewDelegate
  6. signed char
  7. Midnight UTC, 1 January 1970
  8. 4.6.2 (4H1003)
  9. NSIndexSet
  10. 16

Round 2: APIs

  1. @contentMode
  2. @accessibilityHint
  3. +cyanColor
  4. -alertView:clickedButtonAtIndex:
  5. @showsTouchWhenHighlighted
  6. -reloadRowsAtIndexPaths:withRowAnimation:
  7. -tableView:numberOfRowsInSection:
  8. -loadHTMLString:baseURL:
  9. -touchesBegan:withEvent:
  10. @text

Round 3: Picture Round

  1. Apple I
  2. Apple eMac
  3. Apple Bandai Pippin
  4. Apple QuickTake
  5. New Proposed Apple Campus / "Mothership"
  6. Sir Jonathan "Jony" Ive
  7. Scott Forstall
  8. Bob Mansfield
  9. Susan Kare
  10. Kara Swisher & Walt Mossberg

Round 4: Name That Framework!

  1. App Kit
  2. AV Foundation
  3. Publication Subscription
  4. Core Location
  5. Core Data
  6. Search Kit
  7. Address Book
  8. GLKit
  9. Core Bluetooth
  10. Core Image

So how did you fare? Tweet out your score to see how you stack up to your peers!

MKLocalSearch

$
0
0

Look, we get it: people are upset about Apple Maps.

What should have been a crowning feature for iOS 6 became the subject of an official apology due to its embarrassing inaccuracies and the removal of public transportation information.

In all of the hubbub of torch burning and pitchfork raising, you may have completely missed a slew of additions to MapKit in iOS 6.1. Namely: MKLocalSearch.


MKLocalSearch allows developers to find nearby points of interest within a geographic region.

But before you go and rush into using MKLocalSearch, you'll have to know a few things about its friends. You see, MKLocalSearch has its functionality divided across MKLocalSearchRequest and MKLocalSearchResponse:

MKLocalSearchRequest*request=[[MKLocalSearchRequestalloc]init];request.naturalLanguageQuery=@"Restaurants";request.region=mapView.region;MKLocalSearch*search=[[MKLocalSearchalloc]initWithRequest:request];[searchstartWithCompletionHandler:^(MKLocalSearchResponse*response,NSError*error){NSLog(@"Map Items: %@",response.mapItems);}];

MKLocalSearchRequest takes a naturalLanguageQuery, such as "Taxidermists", and an optional bounding geographic region to constrain results. In practice, the region is usually passed from an MKMapView.

MKLocalSearchResponse is returned in the eponymous block handler of MKLocalSearch -startWithCompletionHandler:, and returns an array of MKMapItem objects. Each MKMapItem contains information like name, phoneNumber, url and address information via the placemark property.

If you keep a reference to your MKLocalSearch object, you can optionally -cancel the request, such as on -viewWillDisappear: or the like.

Where's The Beef?

MKLocalSearch is a relatively straight-forward API (albeit perhaps worse off for eschewing a simpler single-class interface)... so what's the big deal?

API limits. Or rather, the lack of them. Let me explain:

Perhaps the most counter-intuitive things about MapKit in iOS 6 is that it's still widely used. Nevermind the "Apple Maps-gate" melodrama, MapKit, even with the introduction of impressive iOS mapping SDKs from Google and MapBox, developers are still using MapKit.

Part of this may be aesthetics, but a lot has to do with a certain level of home-field advantage, too. Because of MapKit's close ties to UIKit, it can be customized more easily and more extensively by third-party developers.

This brings us back to API call limits. When developing with another mapping SDK or geospatial webservice, licensing terms are almost necessarily going to be more limited than what Apple makes available for free. Free is a tough price to beat, and it's all-the-more compelling because there is no worry of going over API limits for tile loading or API calls.

Where Do We Go From Here?

With the introduction of MKLocalSearch, one can be hopeful of more first-party webservices being exposed in a similar fashion. Expanded geospatial search? Or perhaps first-party APIs to iTunes media streaming?

One can dare to dream, after all...


MKLocalSearch provides a simple way to find local points of interest. Because of its no-hassle webservice integration and tight integration with MapKit, any location-based app would do well to take advantage of it.

GPUImage

$
0
0

Here at NSHipster, we're all about diving into the darker corners of Objective-C to learn something new about the systems we interact with every day. Often, this means sifting through Apple frameworks or language features (it is, after all, a lot of what it means to work in Objective-C). However, on occasion, it's nice to take a look to the burgeoning landscape of third-party libraries and frameworks (and there are some truly remarkable ones) for a glimpse of what's new and great outside of Cupertino.

This week, we'll be taking a look at one of the most impressive open source projects you'll find: GPUImage. Buckle up, NSHipsters—if you're not careful, you may well end up creating a camera app by the end of the article.


GPUImage is a BSD-licensed iOS library written by Brad Larson that lets you apply GPU-accelerated filters and other effects to images, live camera video, and movies.

GPU vs. CPU

Every iPhone ships with two processors: a CPU, or Central Processing Unit and a GPU, or Graphics Processing Unit. Each processor has its own strengths, and modern chip architecture (like in the iPhone's A4) integrate the CPU and GPU onto the same physical die.

When you write C or Objective-C code in Xcode, you're generating instructions that will be handled almost exclusively by the CPU. The GPU, by contrast, is a specialized chip that is especially well-suited for computation that can be split out into many small, independent operations, such as graphics rendering. The kinds of instructions understood by the GPU are quite different from that of the CPU, and as such, we write this code in a different language: OpenGL (or specifically, OpenGL ES on the iPhone & iPad).

Check out Jeff LaMarche's GLProgram OpenGL ES 2.0 book for a great introduction to OpenGL ES and the rendering pipeline.

Comparing the performance of GPU-based rendering to CPU rendering for something like video, the differences are staggering:

CPU vs. GPU Frame-Rate (Larger FPS is Better)
CalculationGPU FPSCPU FPSΔ
Thresholding ⨉ 160.004.2114.3⨉
Thresholding ⨉ 233.632.3614.3⨉
Thresholding ⨉ 1001.450.0528.7⨉

"Oh, so it's like Instagram?"

Let me put it this way:

Instagram : GPUImage :: Disposable Camera : NASA Space Optics Manufacturing Center

To put it another way, within GPUImage's APIs lay thousands of camera apps, just waiting for the right combination of filters and a little spark of imagination.

Here's a table of the 125 (!) filters that come with GPUImage:

Color AdjustmentsImage ProcessingBlending ModesVisual Effects
  • Brightness Filter
  • Exposure Filter
  • Contrast Filter
  • Saturation Filter
  • Gamma Filter
  • Levels Filter
  • Color Matrix Filter
  • RGB Filter
  • Hue Filter
  • Tone Curve Filter
  • Highlight Shadow Filter
  • Lookup Filter
  • Amatorka Filter
  • Miss Etikate Filter
  • Soft Elegance Filter
  • Color Invert Filter
  • Grayscale Filter
  • Monochrome Filter
  • False Color Filter
  • Haze Filter
  • Sepia Filter
  • Opacity Filter
  • Solid Color Generator
  • Luminance Threshold Filter
  • Adaptive Threshold Filter
  • Average Luminance Threshold Filter
  • Histogram Filter
  • Histogram Generator
  • Average Color
  • Luminosity
  • Chroma Key Filter
  • Transform Filter
  • Crop Filter
  • Lanczos Resampling Filter
  • Sharpen Filter
  • Unsharp Mask Filter
  • Fast Blur Filter
  • Single Component Fast Blur Filter
  • Gaussian Blur Filter
  • Single Component Gaussian Blur Filter
  • Gaussian Selective Blur Filter
  • Gaussian Blur Position Filter
  • Median Filter
  • Bilateral Filter
  • Tilt Shift Filter
  • Box Blur Filter
  • 3x3 Convolution Filter
  • Sobel Edge Detection Filter
  • Threshold Edge Detection Filter
  • Canny Edge Detection Filter
  • Harris Corner Detection Filter
  • Noble Corner Detection Filter
  • Shi-Tomasi Corner Detection Filter
  • Non Maximum Suppression Filter
  • X/Y Derivative Filter
  • Crosshair Generator
  • Dilation Filter
  • RGB Dilation Filter
  • Erosion Filter
  • RGB Erosion Filter
  • Opening Filter
  • RGB Opening Filter
  • Closing Filter
  • RGB Closing Filter
  • Local Binary Pattern Filter
  • Low Pass Filter
  • High Pass Filter
  • Motion Detector
  • Hough Transform Line Detector
  • Line Generator
  • Motion Blur Filter
  • Zoom Blur Filter
  • Chroma Key Blend Filter
  • Dissolve Blend Filter
  • Multiply Blend Filter
  • Add Blend Filter
  • Subtract Blend Filter
  • Divide Blend Filter
  • Overlay Blend Filter
  • Darken Blend Filter
  • Lighten Blend Filter
  • Color Burn Blend Filter
  • Color Dodge Blend Filter
  • Screen Blend Filter
  • Exclusion Blend Filter
  • Difference Blend Filter
  • Hard Light Blend Filter
  • Soft Light Blend Filter
  • Alpha Blend Filter
  • Source Over Blend Filter
  • Color Burn Blend Filter
  • Color Dodge Blend Filter
  • Normal Blend Filter
  • Color Blend Filter
  • Hue Blend Filter
  • Saturation Blend Filter
  • Luminosity Blend Filter
  • Linear Burn Blend Filter
  • Poisson Blend Filter
  • Mask Filter
  • Pixellate Filter
  • Polar Pixellate Filter
  • Polka Dot Filter
  • Halftone Filter
  • Crosshatch Filter
  • Sketch Filter
  • Threshold Sketch Filter
  • Toon Filter
  • Smooth Toon Filter
  • Emboss Filter
  • Posterize Filter
  • Swirl Filter
  • Bulge Distortion Filter
  • Pinch Distortion Filter
  • Stretch Distortion Filter
  • Sphere Refraction Filter
  • Glass Sphere Filter
  • Vignette Filter
  • Kuwahara Filter
  • Kuwahara Radius 3 Filter
  • Perlin Noise Filter
  • CGAColorspace Filter
  • Mosaic Filter
  • JFAVoronoi Filter
  • Voronoi Consumer Filter

Seriously, the Filter Showcase Example App that comes bundled in the repository could easily retail on the AppStore for $3.99, as-is. Add Twitter integration and a few sound effects, and you could bump that up to a respectable $6.99.

Rendering Pipeline

GPUImage is, at its core, an Objective-C abstraction around a rendering pipeline. Source images from the camera, network, or disk are loaded and manipulated according to a chain of filters, and finally outputted either a view, graphics context, or data stream.

For example, images from the video camera could have a Color Levels filter applied to simulate different types of color blindness and displayed in a live view.

GPUImageVideoCamera*videoCamera=[[GPUImageVideoCameraalloc]initWithSessionPreset:AVCaptureSessionPreset640x480cameraPosition:AVCaptureDevicePositionBack];videoCamera.outputImageOrientation=UIInterfaceOrientationPortrait;GPUImageFilter*filter=[[GPUImageLevelsFilteralloc]initWithFragmentShaderFromFile:@"CustomShader"];[filtersetRedMin:0.299gamma:1.0max:1.0minOut:0.0maxOut:1.0];[filtersetGreenMin:0.587gamma:1.0max:1.0minOut:0.0maxOut:1.0];[filtersetBlueMin:0.114gamma:1.0max:1.0minOut:0.0maxOut:1.0];[videoCameraaddTarget:filter];GPUImageView*filteredVideoView=[[GPUImageViewalloc]initWithFrame:self.view.bounds)];[filteraddTarget:filteredVideoView];[self.viewaddSubView:filteredVideoView];[videoCamerastartCameraCapture];

Or, combining various color blending modes, image effects, and adjustments, you could transform still images into something worthy of sharing with your hipster friends (example taken from FilterKit, which is built on GPUImage):

GPUImageFilterGroup*filter=[[GPUImageFilterGroupalloc]init];GPUImageSaturationFilter*saturationFilter=[[GPUImageSaturationFilteralloc]init];[saturationFiltersetSaturation:0.5];GPUImageMonochromeFilter*monochromeFilter=[[GPUImageMonochromeFilteralloc]init];[monochromeFiltersetColor:(GPUVector4){0.0f,0.0f,1.0f,1.0f}];[monochromeFiltersetIntensity:0.2];GPUImageVignetteFilter*vignetteFilter=[[GPUImageVignetteFilteralloc]init];[vignetteFiltersetVignetteEnd:0.7];GPUImageExposureFilter*exposureFilter=[[GPUImageExposureFilteralloc]init];[exposureFiltersetExposure:0.3];[filteraddGPUFilter:exposureFilter];[filteraddGPUFilter:monochromeFilter];[filteraddGPUFilter:saturationFilter];[filteraddGPUFilter:vignetteFilter];

Looking through all of what GPUImage can do, one can't help but get excited. Easy enough to get started immediately (without needing to know anything about OpenGL) yet performant enough to power whatever you dream up. And not just that, but it also comes with a dizzying number of building blocks—all of the color adjustments, blending modes, and visual effects you could ever want (or never knew you needed).

GPUImage is a rare treat for the open source community, and we as Mac & iOS developers are lucky to have it at our disposal. Use it to make something great, and show others the world in a whole new way.


NSCoding / NSKeyedArchiver

$
0
0

Among the most important architectural decisions made when building an app is how to persist data between launches. The question of how, exactly, to re-create the state of the app from the time it was last opened; of how to describe the object graph in such a way that it can be flawlessly reconstructed next time.

On iOS and Mac OS X, Apple provides two options: Core Data or NSKeyedArchiver / NSKeyedUnarchiver (which serializes <NSCoding>-compliant classes to and from a data representation).

Or rather: three, if you include NSURLCache. In the case of a client-server application, having the client load necessary data on each launch is a viable design, especially when combined with a disk-based cache, which allows stored server responses to be returned immediately from matching requests. In practice, some combination of network and object caching is advisable.

When it comes to modeling, querying, traversing and persisting complex object graphs, there is no substitute for Core Data. Core Data is a big hammer, but not every problem is a nail—much less a sufficiently large nail.

A fair and common comparison of Core Data to NSKeyedArchiver might go something like this:

Core DataNSKeyedArchiver
Entity ModelingYesNo
QueryingYesNo
SpeedFastSlow
Serialization FormatSQLite, XML, or NSDataNSData
MigrationsAutomaticManual
Undo ManagerAutomaticManual

Et cetera. In a heads-up, apples to apples comparison, it looks rather one-sided.

...that is, until you look at it from a slightly different perspective:

Core DataNSKeyedArchiver
Persists StateYesYes
Pain in the AssYesNo

By these measures, NSKeyedArchiver becomes a perfectly reasonable choice in certain situations. Not all apps need to query data. Not all apps need automatic migrations. Not all apps work with large or complex object graphs. And even apps that do may have certain components better served by a simpler solution.

This article will look at the how's, when's, and why's of NSKeyedArchiver and NSCoding. And with this understanding, hopefully provide you, dear reader, with the wisdom to choose the best tool for the job.


NSCoding is a simple protocol, with two methods: -initWithCoder: and encodeWithCoder:. Classes that conform to NSCoding can be serialized and deserialized into data that can be either be archived to disk or distributed across a network.

For example:

@interfaceBook : NSObject<NSCoding>@propertyNSString*title;@propertyNSString*author;@propertyNSUIntegerpageCount;@propertyNSSet*categories;@property(getter=isAvailable)BOOLavailable;@end@implementationBook#pragma mark - NSCoding-(id)initWithCoder:(NSCoder*)decoder{self=[superinit];if(!self){returnnil;}self.title=[decoderdecodeObjectForKey:@"title"];self.author=[decoderdecodeObjectForKey:@"author"];self.pageCount=[decoderdecodeIntegerForKey:@"pageCount"];self.categories=[decoderdecodeObjectForKey:@"categories"];self.available=[decoderdecodeBoolForKey:@"available"];returnself;}-(void)encodeWithCoder:(NSCoder*)encoder{[encoderencodeObject:self.titleforKey:@"title"];[encoderencodeObject:self.authorforKey:@"author"];[encoderencodeInteger:self.pageCountforKey:@"pageCount"];[encoderencodeObject:self.categoriesforKey:@"categories"];[encoderencodeBool:[selfisAvailable]forKey:@"available"];}@end

As you can see, NSCoding is mostly boilerplate. Each property is encoded or decoded as an object or type, using the name of the property of as the key each time. (Some developers prefer to define NSString * constants for each keypath, but this is usually unnecessary).

But boilerplate can be a good things sometimes—with direct control over the entire serialization process, it remains flexible to account for things like:

  • Migrations: If a data model changes—such as adding, renaming, or removing a field—it should maintain compatibility with data serialized in the old format. Apple provides some guidelines on how to go about this in "Forward and Backward Compatibility for Keyed Archives".
  • Archiving non-NSCoding-compatible Classes: According to object-oriented design, objects should take responsibility for encoding and decoding to and from a serialization format. However, when a class doesn't come with NSCoding support built in, it may be left up to class that uses it to help out.

One library that aims to cut down the boilerplate of NSCoding is Mantle, from the good folks over at GitHub. If you're looking for more of the conveniences of Core Data modeling with NSCoding, Mantle is definitely worth a look.


Of course, serialization is only one part of the story. Determining where this data will persist is another question. Again, there are two approaches: writing to the local file system and using NSUserDefaults.

File System

NSKeyedArchiver and NSKeyedUnarchiver provide a convenient API to read / write objects directly to / from disk.

An NSCoding-backed table view controller might, for instance, set its collection property from the file manager

Archiving

[NSKeyedArchiverarchiveRootObject:bookstoFile:@"/path/to/archive"];

Unarchiving

[NSKeyedUnarchiverunarchiveObjectWithFile:@"/path/to/archive"];

NSUserDefaults

Each app has its own database of user preferences, which can store and retrieve any NSCoding-compatible object or C value.

While it is not advisable to store an entire object graph into NSUserDefaults, it can be useful to encode compound objects in this way, such as "current user" objects or API credentials(use Keychain instead).

Archiving

NSData*data=[NSKeyedArchiverarchivedDataWithRootObject:books];[[NSUserDefaultsstandardUserDefaults]setObject:dataforKey:@"books"];

Unarchiving

NSData*data=[[NSUserDefaultsstandardUserDefaults]objectForKey:@"books"];NSArray*books=[NSKeyedUnarchiverunarchiveObjectWithData:data];

As developers, it is our responsibility to understand the goals and needs of our applications, and to resist the urge to over-engineer and prematurely optimize our solutions.

The decision to use Core Data in an application may appear to be a no-brainer, if not harmless. But in many cases, Core Data is discovered to be so unwieldy or unnecessary as to become a real hindrance to making something useful, let alone functional.

And even if most applications would benefit from Core Data at some point, there is wisdom to letting complexity evolve from a simple as necessary. And as far as persistence goes, it doesn't get much simpler than NSCoding.

Core Data Libraries & Utilities

$
0
0

So let's say that, having determined your particular needs and compared all of the alternatives, you've chosen Core Data for your next app.

Nothing wrong with that! Core Data is a great choice for apps that model, persist, and query large object graphs.

Sure it's complicated, cumbersome, and yes, at times, a real pain in the ass—but gosh darn it, some of the best and most popular apps ever built use Core Data. And if it's good enough for them, it's probably good enough for you, too.

...but that's not to say that Core Data can't be improved.

And while there have been many libraries attempting to replace Core Data, there are many more that attempt to make it better. These libraries range from the much-needed dose of syntactic sugar to comprehensive, full-stack frameworks.

This week on NSHipster: a guided tour of the best open source libraries for working with Core Data. Read on to see how you might make the most from your Core Data experience.


For your convenience, the following table is provided. Contained within are the most significant open source libraries and utilities for working with Core Data. This is list is by no means comprehensive, so if you think something is missing or out of place, please tweet @NSHipster—or better yet, submit a pull request.

Wrappers
Magical RecordSaul Mora
Objective-RecordMarin Usalj
SSDataKitSam Soffes
ios-queryableMarty Dill
ReactiveCoreDataJacob Gorban
Adapters
RestKitBlake Watters
AFIncrementalStoreMattt Thompson
MMRecordConrad Stoll
SLRESTfulCoreDataOliver Letterer
OvercoatGuillermo Gonzalez
MantleGitHub
Synchronizers
TICoreDataSyncTim Isted, Michael Fey, Kevin Hoctor, Christian Beer, Tony Arnold, and Danny Greg
UbiquityStoreManagerMaarten Billemont
FireDataJonathan Younger
Utilities
mogeneratorJonathan 'Wolf' Rentzsch

Wrappers

Wrapper libraries provide some much needed syntactic sugar and convenience methods to Core Data's verbose and complicated APIs.

For example, to insert a new managed object into a managed object context, it's a class method on, not NSManagedObject or NSManagedObjectContext as one might reasonably expect, but NSEntityDescription. NSEntityDescription +insertNewObjectForEntityForName:inManagedObjectContext:. What?

There are a number of open source libraries that collectively identify and correct for the roughest patches of the Core Data APIs. Managing a main and private context outside of AppDelegate, convenience method for manipulating and querying managed objects, and so on.

SSDataKit

There is a lot of boilerplate code required to write a Core Data application. This is annoying. In pretty much everything I've written since Core Data came to iOS, I have used the following class.

Inspired by Active Record

It should be no surprise that programmers, having learned how to do things a certain way, will bring those ideas and conventions to other technologies. For the large influx of Ruby developers coming over to iOS, that familiar paradigm was Active Record.

Contrary to popular belief, Core Data is not an Object-Relational Mappers, but rather an object graph and persistence framework, capable of much more than the Active Record pattern alone is capable of. Using Core Data as an ORM necessarily limits the capabilities of Core Data and muddies its conceptual purity. But for many developers longing for the familiarity of an ORM, this trade-off is a deal at twice the price!

Magical Record

MagicalRecord was inspired by the ease of Ruby on Rails' Active Record fetching. The goals of this code are to clean up Core Data related code, allow for clear, simple, one-line fetches, and still allow the modification of the NSFetchRequest when request optimizations are needed.

Objective-Record

This is a lightweight ActiveRecord way of managing Core Data objects. The syntax is borrowed from Ruby on Rails. And yeah, no AppDelegate code. It's fully tested with Kiwi.

Inspired by LINQ

Here's a fun game: the next time you meet a developer coming over from the .NET world, set a timer to see how long it takes them to start raving about LINQ. Seriously, people love LINQ.

For the uninitiated, LINQ is like SQL, but integrated as a language feature. Think NSPredicate, NSSortDescriptor, and Key-Value Coding with a much nicer syntax:

from c in SomeCollection
  where c.SomeProperty < 10
  select new {c.SomeProperty, c.OtherProperty};

ios-queryable

ios-queryable supports LINQ-style query composition and deferred execution, and implements a subset of IEnumerable's methods, including where, take, skip, orderBy, first/firstOrDefault, single/singleOrDefault, count, any, and all.

Inspired by ReactiveCocoa

ReactiveCocoa, which itself brings the functional reactive paradigm to Objective-C, is now being used to bring some functional sanity and order to Core Data. This is still uncharted territory, but the initial results are indeed promising.

ReactiveCoreData

ReactiveCoreData (RCD) is an attempt to bring Core Data into the ReactiveCocoa (RAC) world.

Adapters

Most iOS apps communicate with a webservice in some capacity. For apps using Core Data, it's common for records to be fetched, updated, and deleted from a REST or RPC-style webservice. Maintaining consistency between a local cache and the server is a deceptively tricky enterprise.

Keeping objects up-to-date, removing duplicate records, mapping entities to API endpoints, reconciling conflicts, managing network reachability... these are just some of the challenges a developer faces when creating a robust client-server application.

Fortunately, there are a wealth of open-source libraries that can help alleviate some of this pain.

RestKit

RestKit is a modern Objective-C framework for implementing RESTful web services clients on iOS and Mac OS X. It provides a powerful object mapping engine that seamlessly integrates with Core Data and a simple set of networking primitives for mapping HTTP requests and responses built on top of AFNetworking. It has an elegant, carefully designed set of APIs that make accessing and modeling RESTful resources feel almost magical.

AFIncrementalStore

AFIncrementalStore is an NSIncrementalStore subclass that uses AFNetworking to automatically request resources as properties and relationships are needed.

MMRecord

MMRecord is a block-based seamless web service integration library for iOS and Mac OS X. It leverages the Core Data model configuration to automatically create and populate a complete object graph from an API response. It works with any networking library, is simple to setup, and includes many popular features that make working with web services even easier.

SLRESTfulCoreData

SLRESTfulCoreData builds on top of AFNetworking and SLCoreDataStack and let's you map your JSON REST API to your CoreData model in minutes.

Overcoat

Overcoat is an AFNetworking extension that makes it super simple for developers to use Mantle model objects with a REST client.

Mantle

Mantle makes it easy to write a simple model layer for your Cocoa or Cocoa Touch application.

Synchronizers

Whereas adapters synchronize information through an existing, general purpose interface such as REST, synchronizers use a more direct protocol, offering better integration and performance at the expense of portability and generality.

TICoreDataSync

Automatic synchronization for Core Data Apps, between any combination of Mac OS X and iOS: Mac to iPhone to iPad to iPod touch and back again

UbiquityStoreManager

UbiquityStoreManager is a controller that implements iCloud integration with Core Data for you.

FireData

FireData seamlessly integrates Core Data with Firebase.

Utilities

We would be remiss to survey the open source Core Data ecosystem without mentioning Mogenerator. Among one of the surviving projects from the pre-iPhone era, Mogenerator has become indispensable to developers over the years. Although much has changed about Core Data over the years, the one constant has been Apple's characteristic lack of comprehensive tooling. Fortunately, Mr. Wolf Rentzsch has us covered.

Mogenerator

mogenerator is a command-line tool that, given an .xcdatamodel file, will generate two classes per entity. The first class, _MyEntity, is intended solely for machine consumption and will be continuously overwritten to stay in sync with your data model. The second class, MyEntity, subclasses _MyEntity, won't ever be overwritten and is a great place to put your custom logic.


Remember: there is no silver bullet. There is no one-size-fits-all solution. Just as Core Data may only be advisable in particular circumstances, so too are the aforementioned Core Data libraries.

Dividing the ecosystem up into broad categories is informative if only to help identify the relative strengths and trade-offs of each library. Only you can determine (yes, sometimes through trial and error) which solution is the best for you.

Unit Testing

$
0
0

Unit Testing is an emotional topic for developers. It inspires a sense of superiority to its most zealous adherents, and evokes a feeling of inadequacy to non-practitioners. Cargo Cults like TDD stake their reputation on unit testing to the point of co-opting and conflating utility with morality.

It's as close to a religious matter as programmers get, aside from the tabs-versus-spaces debate.

Objective-C developers have, for the most part, remained relatively apathetic to Unit Testing ("There's that SenTest thing, but who uses that, really?"). Between static typing, typically manageable project sizes, and a compiler advanced enough to rewrite code for you, unit testing isn't as much of a necessity as it is for more dynamic languages like Ruby (at least in practice).

But that's not to say that Objective-C developers wouldn't benefit from unit testing. In fact, as Objective-C continues to become more collaborative, with growing participation in the open source community, automated testing will become a necessity.

This week NSHipster will explore the world of unit testing frameworks, and how to set up an automated build system with Travis CI.


Unit Testing is a tool, just like any other tool. Its purpose is to make us better at our jobs, which is to produce robust, maintainable software.

It's a simple enough premise: write code to construct environments that exercise the particular behavior of a given method, function, class, or feature. Variables are isolated in a scientific manner, so as to test assumptions with logical atomicity.

OCUnit

OCUnit, a.k.a. SenTestingKit, was integrated into Xcode 2.1 circa WWDC 2005, as a result of its use in the development of Core Data 1.0. Developed by Sen:te, OCUnit is actually one of the first unit testing libraries written for any language.

Unit Tests were added into a separate testing target in the Xcode Project. Each test file defines an SenTestCase subclass, which implements a series of methods beginning with the word test. C assert-style macros are used to fail tests if the specified condition is not met. Each test is run in sequence, independently of one another, with the results logged afterwards:

#import <SenTestingKit/SenTestingKit.h>#import "Person.h"@interfaceTestPerson : SenTestCase@end@implementationTestPerson-(void)testFullName{Person*person=[[Personalloc]init];person.firstName=@"Pablo";person.lastName=@"Picasso";STAssertEqualObjects([personfullName],@"Pablo Picasso",nil);}

The SenTestingKit assertions are about what you'd expect, offering bread-and-butter equality, existence, and truth checks:

  • STAssertNil()
  • STAssertNotNil()
  • STAssertTrue()
  • STAssertFalse()
  • STAssertEqualObjects()
  • STAssertEquals()
  • STAssertEqualsWithAccuracy()
  • STAssertThrows()
  • STAssertThrowsSpecific()
  • STAssertThrowsSpecificNamed()
  • STAssertNoThrow()
  • STAssertNoThrowSpecific()
  • STAssertNoThrowSpecificNamed()
  • STAssertTrueNoThrow()
  • STAssertFalseNoThrow()
  • STFail()

And yet, as useful as tests are, they necessarily introduce friction into a development cycle. When project pressures begin to weigh, tests are the first thing to be thrown overboard. At some point, the tests stop passing ("we can worry about that later—now we have to ship!")

The only chance testing has to remain relevant in high-pressure situations is to reduce that friction in development. Essentially, tests need to become both easier to write and easier to run.

Open Source Libraries

There are a myriad of open source libraries that attempt to make testing more palatable by way of syntactic sugar and features like method stubs, mock objects, and promises.

Here's a list of some of the most useful open source libraries for unit testing:

Mock Objects
OCMockErik Doernenburg
OCMockitoJon Reid
Matchers
ExpectaPeter Jihoon Kim
OCHamcrestJon Reid
BDD / TDD
SpectaPeter Jihoon Kim
KiwiAllen Ding
CedarPivotal Labs
Frameworks
GHUnitGabriel Handford

Automated Testing

Making tests easier to write is one thing, but getting them to run without affecting productivity is quite another.

Jenkins

For a long time, installing Jenkins on a dedicated Mac Mini was the state-of-the-art for automated build servers.

Aside from the fact that it's kinda the worst thing ever to set-up, you can do a lot of cool things like notifying build status over IM or IRC, automatically distributing builds to TestFlight or HockeyApp with Shenzhen, and generating documentation with AppleDoc.

Travis

Until recently, automated unit testing for Objective-C was the privilege of projects that could dedicate the time and money to setup a CI server. Travis CI made CI available to the masses.

CI for Objective-C is more difficult than for other languages, because it needs to be done on a Mac. For economic reasons, there just isn't a market for cloud-based OS X environments like there is for Linux. Fortunately, SauceLabs has built such a virtualized Mac cloud, and is graciously donating some of it to run tests for open source Objective-C projects on Travis-CI.

For an example of automated Objective-C unit testing in the wild, check out how AFNetworking does it.

The Tests subdirectory contains separate projects for iOS and OS X targets, as well as a Podfile, which specifies all of the testing library dependencies. AFNetworking executes a Rake task, which shells out to xctool.

All of the configuration for setup is defined in .travis.yml:

.travis.yml

language: objective-c
before_install:
  - brew update
  - brew install xctool --HEAD
  - cd Tests && pod install && cd $TRAVIS_BUILD_DIR
  - mkdir -p "Tests/AFNetworking Tests.xcodeproj/xcshareddata/xcschemes" && cp Tests/Schemes/*.xcscheme "Tests/AFNetworking Tests.xcodeproj/xcshareddata/xcschemes/"
script: rake test

Full documentation for the Travis configuration file can be found on Travis-CI.org.


Once again, the direction of Objective-C has been directly influenced by the Ruby community. Those guys and gals are serious about testing. It's not like we should complain, though: between CocoaPods, RubyMotion, and Nomad, Ruby has made Objective-C development better by several orders of magnitude.

The bottom line is that testing has come to Objective-C. It's not always necessary, and it's certainly not a silver bullet for writing great software, but it's proven itself invaluable (especially for open source development). So give it a try now, before not testing becomes seriously uncool.

NSDataDetector

$
0
0

Machines speak in binary, while humans speak in riddles, half-truths, and omissions.

And until humanity embraces RDF for all of their daily interactions, a large chunk of artificial intelligence is going to go into figuring out what the heck we're all talking about.

Because in the basic interactions of our daily lives—meeting people, making plans, finding information online—there is immense value in automatically converting from implicit human language to explicit structured data, so that it can be easily added to our calendars, address books, maps, and reminders.

Fortunately for Cocoa developers, there's an easy solution: NSDataDetector.


NSDataDetector is a subclass of NSRegularExpression, but instead of matching on an ICU pattern, it detects semi-structured information: dates, addresses, links, phone numbers and transit information.

It does all of this with frightening accuracy. NSDataDetector will match flight numbers, address snippets, oddly formatted digits, and even relative deictic expressions like "next Saturday at 5".

You can think of it as a regexp matcher with incredibly complicated expressions that can extract information from natural language (though its actual implementation details may be somewhat more complicated than that).

NSDataDetector objects are initialized with a bitmask of types of information to check, and then passed strings to match on. Like NSRegularExpression, each match found in a string is represented by a NSTextCheckingResult, which has details like character range and match type. However, NSDataDetector-specific types may also contain metadata such as address or date components.

NSError*error=nil;NSDataDetector*detector=[NSDataDetectordataDetectorWithTypes:NSTextCheckingTypeAddress|NSTextCheckingTypePhoneNumbererror:&error];NSString*string=@"123 Main St. / (555) 555-5555";[detectorenumerateMatchesInString:stringoptions:kNilOptionsrange:NSMakeRange(0,[stringlength])usingBlock:^(NSTextCheckingResult*result,NSMatchingFlagsflags,BOOL*stop){NSLog(@"Match: %@",result);}];

When initializing NSDataDetector, be sure to specify only the types you're interested in. With each additional type to be checked comes a nontrivial performance cost.

Data Detector Match Types

Because of how much NSTextCheckingResult is used for, it's not immediately clear which properties are specific to NSDataDetector. For your reference, here is a table of the different NSTextCheckingTypes for NSDataDetector matches, and their associated properties:

TypeProperties
NSTextCheckingTypeDate
  • date
  • duration
  • timeZone
NSTextCheckingTypeAddress
  • addressComponents*
    • NSTextCheckingNameKey
    • NSTextCheckingJobTitleKey
    • NSTextCheckingOrganizationKey
    • NSTextCheckingStreetKey
    • NSTextCheckingCityKey
    • NSTextCheckingStateKey
    • NSTextCheckingZIPKey
    • NSTextCheckingCountryKey
    • NSTextCheckingPhoneKey
NSTextCheckingTypeLink
  • url
NSTextCheckingTypePhoneNumber
  • phoneNumber
NSTextCheckingTypeTransitInformation
  • components*
    • NSTextCheckingAirlineKey
    • NSTextCheckingFlightKey
*NSDictionary properties have values at defined keys.

Data Detection on iOS

Somewhat confusingly, iOS also defines UIDataDetectorTypes. A bitmask of these values can be set as the dataDetectorTypes of a UITextView to have detected data automatically linked in the displayed text.

UIDataDetectorTypes is distinct from NSTextCheckingTypes in that equivalent enum constants (e.g. UIDataDetectorTypePhoneNumber and NSTextCheckingTypePhoneNumber) do not have the same integer value, and not all values in one are found in the other. Converting from UIDataDetectorTypes to NSTextCheckingTypes can be accomplished with a function:

staticinlineNSTextCheckingTypeNSTextCheckingTypesFromUIDataDetectorTypes(UIDataDetectorTypesdataDetectorType){NSTextCheckingTypetextCheckingType=0;if(dataDetectorType&UIDataDetectorTypeAddress){textCheckingType|=NSTextCheckingTypeAddress;}if(dataDetectorType&UIDataDetectorTypeCalendarEvent){textCheckingType|=NSTextCheckingTypeDate;}if(dataDetectorType&UIDataDetectorTypeLink){textCheckingType|=NSTextCheckingTypeLink;}if(dataDetectorType&UIDataDetectorTypePhoneNumber){textCheckingType|=NSTextCheckingTypePhoneNumber;}returntextCheckingType;}

If you're looking for an easy way to use NSDataDetector in your iOS app, you may want to check out TTTAttributedLabel, a drop-in replacement for UILabel that supports attributed strings, and (as of 1.7.0) automatic data detection of NSTextCheckingTypes.


Do I detect some disbelief of how easy it is to translate between natural language and structured data? This should not be surprising, given how insanelygreat Cocoa's linguistic APIs are.

Don't make your users re-enter information by hand just because of a programming oversight. Take advantage of NSDataDetector in your app to unlock the structured information already hiding in plain sight.

NSHipster Quiz #2

$
0
0

On June 11th, we organized an NSHipster Pub Quiz for WWDC attendees. Like our first quiz, questions ranged from random Apple trivia to obscure framework questions. The event was hosted by New Relic, and sponsored by Heroku& Mutual Mobile. About 100 developers attended the event, with the team "UIResponders" taking top prize.

For everyone that couldn't make it to the event, here's an opportunity to play along at home. Here are some ground rules:

  • There are 4 Rounds, with 10 questions each
  • Record answers on a separate sheet of paper
  • Each correct answer to a question gets you 1 point (unless otherwise specified)
  • Play with up to 5 friends for maximum enjoyment
  • Don't be lame and look things up on the Internet or in Xcode

Round 1: General Knowledge

  1. Mac OS 10.9 Mavericks is named after a surf spot in Northern California. What was the surf spot named after?
  2. What is the Objective-C Type Encoding of NSError **?
  3. What is the name of the command line utility that generates a .strings file from Objective-C source code with NSLocalizedString?
  4. What NSArray method was available since 10.6, but only made public as of 10.9?
  5. What is the name of the open source project whose C/C++ libraries power NSRegularExpression, CFStringTransform, and other Unicode features in Cocoa?
  6. On May 19, 2001 Apple opened its first 2 retail stores. Where were they? (1 point for each exact location, or ½‎ for each state)
  7. What is the name of the private Apple TV framework responsible for appliance UI?
  8. Which Apple VP said "Can't innovate anymore,
 my ass!"?
  9. List all of the rooms in Moscone West named after San Francisco neighborhoods, starting at Level 2 (1 point for each room)
  10. Complete the following verse:

We've come too far To give up who we are



She's up all night to the sun...

Round 2: Before & After

What are the following better known as today?

  1. Yellow Box
  2. AppleSearch
  3. Jaguar (i.e. "Mac OS X 10.__"?)
  4. Rendezvous
  5. SoundJam
  6. Six Pack
  7. Universal Access
  8. Graphics Group (semi-related to Apple)
  9. 20525 Mariani Ave.
  10. Yerba Buena (has to do with California, not Apple)

Round 3: Picture Round

  • 1. Which WWDC keynote was this from?

Question 1

  • 2. Which WWDC keynote was this from?

Question 2

  • 3. Which WWDC keynote was this from?

Question 3

  • 4. Which WWDC keynote was this from?

Question 4

  • 5. WTF is this?

Question 5

  • 6. What is this?

Question 6

  • 7. What is this?

Question 7

  • 8. What is this? (and which generation?)

Question 8

  • 9. Which "Core" framework is represented by this logo?

Question 9

  • 10. Everybody loves Craig /fɛdɹ̩igi/ (Pictured). How do you spell his last name?

Question 10

Round 4: Name That Framework!

For each question, a list of three classes from the same framework have been listed without their two-letter namespace prefix. Name the framework that they all belong to!

  1. Call, CallCenter, Carrier
  2. Attitude, LogItem, Magnetometer Data
  3. IdentifierManager
  4. Request, ComposeViewController, ServiceTypes.h
  5. Metadata, FileWrapper, FileManager
  6. Alarm, RecurrenceEnd, Source
  7. NotificationBanner, Player, SessionError
  8. Null, Zone, Coder
  9. Attribute Description, Relationship Description, Property Mapping
  10. Map Table, Hash Table, Pointer Array

Answers

Round 1: General Knowledge

  1. A white-haired German Shepherd named Maverick#History) (anything about a dog gets the point)
  2. ^@
  3. genstrings
  4. NSArray -firstObject
  5. ICU (International Components for Unicode)
  6. Tysons Corner, Virginia & Glendale, California
  7. BackRow
  8. Phil Schiller
  9. Pacific Heights, Mission, Nob Hill, Russian Hill, Marina, Presidio
  10. "So let's raise the bar / And our cups to the stars"

Round 2: Before & After

  1. Cocoa
  2. Sherlock
  3. Mac OS X 10.2
  4. Bonjour
  5. iTunes
  6. System 6 / Mac OS 6
  7. Accessibility
  8. Pixar
  9. 1 Infinite Loop
  10. San Francisco

Round 3: Picture Round

  1. 2011
  2. 2009
  3. 2012
  4. 2008
  5. eMate 300
  6. Xserve RAID
  7. iSight
  8. 3rd gen. iPod Shuffle
  9. Core Audio
  10. "Federighi"

Round 4: Name That Framework!

  1. Core Telephony
  2. Core Motion
  3. Ad Support
  4. Social
  5. Foundation
  6. EventKit
  7. Game Kit
  8. Foundation
  9. Core Data
  10. Foundation or Core Foundation (2 points if you got both)

So how did you fare? Tweet out your score to see how you stack up to your peers!

We'll be announcing another pub quiz soon, so be sure to sign up here to be the first to know about it!

Viewing all 382 articles
Browse latest View live