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

NSUndoManager

$
0
0

We all make mistakes. Thankfully, Foundation comes to our rescue for more than just our misspellings. Cocoa includes a simple yet robust API for undoing or redoing actions through NSUndoManager.

By default, each application window has an undo manager, and any object in the responder chain can manage a custom undo manager for performing undo and redo operations local to their respective view. UITextField and UITextView use this functionality to automatically provide support for undoing text edits while first responder. However, indicating whether other actions can be undone is an exercise left for the app developer.

Creating an undoable action requires three steps: performing a change, registering an “undo operation” which can reverse the change, and responding to a request to undo the change.

Undo Operations

To show an action can be undone, register an “undo operation” while performing the action. The Undo Architecture documentation defines an “undo operation” as:

A method for reverting a change to an object, along with the arguments needed to revert the change.

The operation specifies:

  • The object to receive a message if an undo is requested
  • The message to send and
  • The arguments to pass with the message

If the method invoked by the undo operation also registers an undo operation, the undo manager provides redo support without extra work, as it is “undoing the undo”.

There are two types of undo operations, “simple” selector-based undo and complex “NSInvocation-based undo”.

Registering a Simple Undo Operation

To register a simple undo operation, invoke NSUndoManger -registerUndoWithTarget:selector:object: on a target which can undo the action. The target is not necessarily the modified object, and is often a utility or container which manages the object’s state. Specify the name of the undo action at the same time, using NSUndoManager -setActionName:. The undo dialog shows the name of the action, so it should be localized.

funcupdateScore(score:NSNumber){undoManager.registerUndoWithTarget(self,selector:Selector("updateScore:"),object:myMovie.score)undoManager.setActionName(NSLocalizedString("actions.update",comment:"Update Score"))myMovie.score=score}
-(void)updateScore:(NSNumber*)score{[undoManagerregisterUndoWithTarget:selfselector:@selector(updateScore:)object:myMovie.score];[undoManagersetActionName:NSLocalizedString(@"actions.update",@"Update Score")];myMovie.score=score;}

Registering a Complex Undo Operation with NSInvocation

Simple undo operations may be too rigid for some uses, as undoing an action may require more than one argument. In these cases, we can leverage NSInvocation to record the selector and arguments required. Calling prepareWithInvocationTarget: records which object will receive the message which will make the change.

funcmovePiece(piece:ChessPiece,row:UInt,column:UInt){letundoController:ViewController=undoManager?.prepareWithInvocationTarget(self)asViewControllerundoController.movePiece(piece,row:piece.row,column:piece.column)undoManager?.setActionName(NSLocalizedString("actions.move-piece","Move Piece"))piece.row=rowpiece.column=columnupdateChessboard()}
-(void)movePiece:(ChessPiece*)piecetoRow:(NSUInteger)rowcolumn:(NSUInteger)column{[[undoManagerprepareWithInvocationTarget:self]movePiece:pieceToRow:piece.rowcolumn:piece.column];[undoManagersetActionName:NSLocalizedString(@"actions.move-piece",@"Move Piece")];piece.row=row;piece.column=column;[selfupdateChessboard];}

The magic here is that NSUndoManager implements forwardInvocation:. When the undo manager receives the message to undo -movePiece:row:column:, it forwards the message to the target since NSUndoManager does not implement this method.

Performing an Undo

Once undo operations are registered, actions can be undone and redone as needed, using NSUndoManager -undo and NSUndoManager -redo.

Responding to the Shake Gesture on iOS

By default, users trigger an undo operation by shaking the device. If a view controller should handle an undo request, the view controller must:

  1. Be able to become first responder
  2. Become first responder once its view appears,
  3. Resign first responder when its view disappears

When the view controller then receives the motion event, the operating system presents a dialog to the user when undo or redo actions are available. The undoManager property of the view controller will handle the user’s choice without further involvement.

classViewController:UIViewController{overridefuncviewDidAppear(animated:Bool){super.viewDidAppear(animated)becomeFirstResponder()}overridefuncviewWillDisappear(animated:Bool){super.viewWillDisappear(animated)resignFirstResponder()}overridefunccanBecomeFirstResponder()->Bool{returntrue}// ...}
@implementationViewController-(void)viewDidAppear:(BOOL)animated{[superviewDidAppear:animated];[selfbecomeFirstResponder];}-(void)viewWillDisappear:(BOOL)animated{[superviewWillDisappear:animated];[selfresignFirstResponder];}-(BOOL)canBecomeFirstResponder{returnYES;}// ...@end

Customizing the Undo Stack

Grouping Actions Together

All undo operations registered during a single run loop will be undone together, unless “undo groups” are otherwise specified. Grouping allows undoing or redoing many actions at once. Although each action can be performed and undone individually, if the user performs two at once, undoing both at once preserves a consistent user experience.

funcreadAndArchiveEmail(email:Email){undoManager?.beginUndoGrouping()markEmail(email,read:true)archiveEmail(email)undoManager?.setActionName(NSLocalizedString("actions.read-archive",comment:"Mark as Read and Archive"))undoManager?.endUndoGrouping()}funcmarkEmail(email:Email,read:Bool){letundoController:ViewController=undoManager?.prepareWithInvocationTarget(self)asViewControllerundoController.markEmail(email,read:email.read)undoManager?.setActionName(NSLocalizedString("actions.read",comment:"Mark as Read"))email.read=read}funcarchiveEmail(email:Email){letundoController:ViewController=undoManager?.prepareWithInvocationTarget(self)asViewControllerundoController.moveEmail(email,toFolder:"Inbox")undoManager?.setActionName(NSLocalizedString("actions.archive",comment:"Archive"))moveEmail(email,toFolder:"All Mail")}
-(void)readAndArchiveEmail:(Email*)email{[undoManagerbeginUndoGrouping];[selfmarkEmail:emailasRead:YES];[selfarchiveEmail:email];[undoManagersetActionName:NSLocalizedString(@"actions.read-archive",@"Mark as Read and Archive")];[undoManagerendUndoGrouping];}-(void)markEmail:(Email*)emailasRead:(BOOL)isRead{[[undoManagerprepareWithInvocationTarget:self]markEmail:emailasRead:[emailisRead]];[undoManagersetActionName:NSLocalizedString(@"actions.read",@"Mark as Read")];email.read=isRead;}-(void)archiveEmail:(Email*)email{[[undoManagerprepareWithInvocationTarget:self]moveEmail:emailtoFolder:@"Inbox"];[undoManagersetActionName:NSLocalizedString(@"actions.archive",@"Archive")];[selfmoveEmail:emailtoFolder:@"All Mail"];}

Clearing the Stack

Sometimes the undo manager’s list of actions should be cleared to avoid confusing the user with unexpected results. The most common cases are when the context changes dramatically, like changing the visible view controller on iOS or externally made changes occurring on an open document. When that time comes, the undo manager’s stack can be cleared using NSUndoManager -removeAllActions or NSUndoManager -removeAllActionsWithTarget: if finer granularity is needed.

Caveats

If an action has different names for undo versus redo, check whether an undo operation is occurring before setting the action name to ensure the title of the undo dialog reflects which action will be undone. An example would be a pair of opposing operations, like adding and removing an object:

funcaddItem(item:NSObject){undoManager?.registerUndoWithTarget(self,selector:Selector("removeItem:"),object:item)ifundoManager?.undoing==false{undoManager?.setActionName(NSLocalizedString("action.add-item",comment:"Add Item"))}myArray.append(item)}funcremoveItem(item:NSObject){ifletindex=find(myArray,item){undoManager?.registerUndoWithTarget(self,selector:Selector("addItem:"),object:item)ifundoManager?.undoing==false{undoManager?.setActionName(NSLocalizedString("action.remove-item",comment:"Remove Item"))}myArray.removeAtIndex(index)}}
-(void)addItem:(id)item{[undoManagerregisterUndoWithTarget:selfselector:@selector(removeItem:)object:item];if(![undoManagerisUndoing]){[undoManagersetActionName:NSLocalizedString(@"actions.add-item",@"Add Item")];}[myArrayaddObject:item];}-(void)removeItem:(id)item{[undoManagerregisterUndoWithTarget:selfselector:@selector(addItem:)object:item];if(![undoManagerisUndoing]){[undoManagersetActionName:NSLocalizedString(@"actions.remove-item",@"Remove Item")];}[myArrayremoveObject:item];}

If your test framework runs many tests as a part of one run loop (like Kiwi), clear the undo stack between tests in teardown. Otherwise tests will share undo state and invoking NSUndoManager -undo during a test may lead to unexpected results.


There are even more ways to refine behavior with NSUndoManager, particularly for grouping actions and managing scope. Apple also provides usability guidelines for making undo and redo accessible in an expected and delightful way.

We all may wish to live without mistakes, but Cocoa gives us a way to let our users live with fewer regrets as it makes some actions easily changeable.


The Death of Cocoa

$
0
0

Cocoa is the de facto standard library of Objective-C, containing many of the essential frameworks for working in the language, such as Foundation, AppKit, and Core Data. Cocoa Touch is basically just Cocoa with UIKit substituted for AppKit, and is often used interchangeably with Cocoa to refer to the system frameworks on iOS.

For many of us, the simplicity, elegance, and performance of Apple’s hardware and software working together are the reason why we build on their platforms. Indeed, no shortage of words have been penned on this site in adulation of Cocoa’s design and functionality.

And yet, after just a few months of working with Swift, Cocoa has begun to lose its luster. We all saw Swift as the beginning of the end for Objective-C, but Cocoa? (It wouldn’t be the first time an Apple standard library would be made obsolete. Remember Carbon?)

Swift is designed with modern language features that allow for safer, more performant code. However, one could be forgiven for seeing Swift as little more than a distraction for the compiler tools team, as very few of Swift’s advantages trickle down into conventional application usage.

Having Objective-C and Swift code interoperate in a meaningful way from launch was a strategic—and arguably necessary—decision. Allowing the more adventurous engineers within a team a low-risk way to introduce Swift into existing code bases has been crucial to the wide adoption the new language has already seen. But for all of the effort that’s been put into source mapping and API auditing, there’s an argument to be made that Cocoa has become something of a liability.

What if we were to build a new Foundation from the Swift Standard Library? What would we do differently, and how could we learn from the mistakes of our past? This may seem an odd thesis for NSHipster, a site founded upon a great deal of affection for Objective-C and Cocoa, but it’s one worth exploring.

So to close out this historic year for Apple developers, let’s take a moment to look forward at the possibilities going forward.


If I have seen further it is by standing on the shoulders of giants.Isaac Newton

We owe all of our productivity to standard libraries.

When done well, standard libraries not only provide a common implementation of the most useful programming constructs, but they clarify those concepts in a transferable way. It’s when a language’s standard library diverges from existing (or even internal) convention that things go south.

For example, NSURLComponents conforms to RFC 3986—a fact made explicit in the documentation. Not only do API consumers osmotically absorb the proper terminology and concepts as a byproduct of usage, but newcomers to the API that are already familiar with RFC 3986 can hit the ground running. (And how much easier it is to write documentation; just “RTFM” with a link to the spec!)

Standard libraries should implement standards.

When we talk about technologies being intuitive, what we usually mean is that they’re familiar. Standards from the IETF, ISO, and other bodies should be the common ground on which any new standard library should be built.

Based on this assertion, let’s take a look at some specific examples of what Cocoa does, and how a new Swift standard library could improve.

Numbers

NSNumber exists purely as an object wrapper around integer, float, double, and boolean primitives. Without such concerns in Swift, there is no practical role for such a construct.

Swift’s standard library has done a remarkable job in structuring its numeric primitives, through a clever combination of top-level functions and operators and type hierarchies. (And bonus points for including literals for binary, octal, and hexadecimal in addition to decimal). For lack of any real complaints about what’s currently there, here are some suggestions for what might be added:

Strings

The peril of strings is that they can encode so many different kinds of information. As written previously:

Strings are perhaps the most versatile data type in computing. They’re passed around as symbols, used to encode numeric values, associate values to keys, represent resource paths, store linguistic content, and format information.

NSString is perhaps too versatile, though. Although it handles Unicode like a champ, the entire API is burdened by the conflation of strings as paths. stringByAppendingPathComponent: and its ilk are genuinely useful, but this usefulness ultimately stems from a misappropriation of strings as URLs.

Much of this is due to the fact that @"this" (a string literal) is much more convenient than [NSURL URLWithString:@"that"] (a constructor). However, with Swift’s literal convertibles, it can be just as easy to build URL or Path values.

One of the truly clever design choices for Swift’s String is the internal use of encoding-independent Unicode characters, with exposed “views” to specific encodings:

  • A collection of UTF-8 code units (accessed with the string’s utf8 property)
  • A collection of UTF-16 code units (accessed with the string’s utf16 property)
  • A collection of 21-bit Unicode scalar values, equivalent to the string’s UTF-32 encoding form (accessed with the string’s unicodeScalars property)

One of the only complaints of Swift Strings are how much of its functionality is hampered by the way functionality is hidden in top-level functions. Most developers are trained to type . and wait for method completion for something like “count”; it’s less obvious to consult the top-level countElements function. (Again, as described in the Default Protocol Implementations article, this could be solved if either Xcode or Swift itself allowed automatic bridging of explicit and implicit self in functions).

URI, URL, and URN

An ideal URL implementation would be a value-type (i.e. struct) implementation of NSURLComponents, which would take over all of the aforementioned path-related APIs currently in NSString. Something along these lines. A clear implementation of URI schemes, according to RFC 4395, could mitigate the conflation of file (file://) URLs as they are currently in NSURL. A nice implementation of URNs, according to RFC 2141 would do wonders for getting developers to realize what a URN is, and how URIs, URLs, and URNs all relate to one another. (Again, it’s all about transferrable skills).

Data Structures

Swift’s functional data structures, from generators to sequences to collections, are, well, beautiful. The use of Array and Dictionary literals for syntactic sugar strikes a fine balance with the more interesting underlying contours of the Standard Library.

Building on these strong primitives, it is remarkably easy to create production-ready implementations of the data structures from an undergraduate Computer Science curriculum. Armed with Wikipedia and a spare afternoon, pretty much anyone could do it—or at least get close.

It’d be amazing if the Swift standard library provided canonical implementations of a bunch of these (e.g. Tree, Singly- Doubly-Linked Lists, Queue / Stack). But I’ll only make the case for one: Set.

The three big collections in Foundation are NSArray, NSDictionary, and NSSet (and their mutable counterparts). Of these, Set is the only one currently missing. As a fundamental data structure, they are applicable to a wide variety of use cases. Specifically for Swift, though, Set could resolve one of the more awkward corners of the language—RawOptionSetType.

For your consideration, Nate Cook has built a nice, complete implementation of Set.

Dates & Times

The calendaring functionality is some of the oldest and most robust in Cocoa. Whereas with most other languages, date and time programming is cause for fear, one does not get the same sense of dread when working with NSDate and NSCalendar. However, it suffers from being difficult to use and impossible to extend.

In order to do any calendaring calculations, such as getting the date one month from today, one would use NSCalendar and NSDateComponents. That’s the correct way to do it, at least… a majority of developers probably still use dateWithTimeIntervalSinceNow: with a constant number of seconds hardcoded. Tragically, it’s not enough for an API to do things the right way, it must also be easier than doing it the wrong way.

Another shortfall (albeit incredibly minor) of NSCalendar is that it doesn’t allow for new calendars to be added. For someone doing their darnedest to advocate conversion to the French Republican Calendar, this is bothersome.

Fortunately, all of the new language features of Swift could be used to solve both of these problems in a really elegant way. It’d take some work to implement, but a calendaring system based on generics could really be something. If anyone wants to take me up on that challenge, here are some ideas.

Interchange Formats

One of the most astonishing things about Objective-C is how long it took for it to have a standard way of working with JSON (iOS 5 / OS X Lion!). Developers hoping to work with the most popular interchange format for new web services were forced to choose from one of a handful of mutually incompatible third-party libraries.

However, NSJSONSerialization is such a miserable experience in Swift that we’re repeating history with a new crop of third-party alternatives:

letdata:NSDatavarerror:NSError?=nilifletJSON=NSJSONSerialization.JSONObjectWithData(data,options:nil,error:&error)as?NSDictionary{forproductinJSON["products"]!asNSArray{letname:String=product["name"]asStringletprice:Double=product["price"]asDouble}}
NSData*data;NSError*error=nil;idJSON=[NSJSONSerializationJSONObjectWithData:dataoptions:0error:&error];if(!error){for(idproductinJSON[@"products"]){NSString*name=product[@"name"];NSNumber*price=product[@"price"];// ...}}

In defense of Apple, I once asked an engineer at a WWDC Lab why it took so long for iOS to support JSON. Their answer made a lot of sense. Paraphrasing:

Apple is a company with a long view of technology. It’s really difficult to tell whether a technology like JSON is going to stick, or if it’s just another fad. Apple once released a framework for PubSub, which despite not being widely known or used, still has to be supported for the foreseeable future. Each technology is a gamble of engineering resources.

Data marshaling and serialization are boring tasks, and boring tasks are exactly what a standard library should take care of. Apple knew this when developing Cocoa, which has robust implementations for both text and binary property lists, which are the lifeblood of iOS and OS X. It may be difficult to anticipate what other interchange formats will be viable in the long term, but providing official support for emerging technologies on a probationary basis would do a lot to improve things for developers.

Regular Expressions

Regexes are a staple of scripting languages—enough so that they often have a dedicated syntax for literals, / /. If Swift ever moves on from Cocoa, it would be well-advised to include a successor to NSRegularExpression, such as this wrapper.

Errors

Objective-C is rather exceptional in how it uses error pointers (NSError **) to communicate runtime failures rather than @throw-ing exceptions. It’s a pattern every Cocoa developer should be familiar with:

NSError*error=nil;BOOLsuccess=[[NSFileManagerdefaultManager]moveItemAtPath:@"/path/to/target"toPath:@"/path/to/destination"error:&error];if(!success){NSLog(@"%@",error);}

The out parameter for error is a workaround for the fact that Objective-C can only have a single return value. If something goes wrong, the NSError instance will be populated with a new object with details about the issue.

In Swift, this pattern is unnecessary, since a method can return a tuple with an optional value and error instead:

funcmoveItemAtPath(from:StringtoPathto:String)->(Bool,NSError?){...}

We can even take things a step further and define a generic Result type, with associated values for success and failure cases:

structError{...}publicenumResult<T>{caseSuccess(T)caseFailure(Error)}

Using this new pattern, error handling is enforced by the compiler in order to exhaust all possible cases:

HTTPClient.getUser{(result)inswitchresult{case.Success(letuser):// Successcase.Failure(leterror):// Failure}}

Patterns like this have emerged from a community eager to improve on existing patterns in pure Swift settings. It would be helpful for a standard library to codify the most useful of these patterns in order to create a shared vocabulary that elevates the level of discourse among developers.

AppKit & UIKit

AppKit and UIKit are entire topics unto themselves. It’s much more likely that the two would take further steps to unify than be rewritten or adapted to Swift anytime soon. A much more interesting question is whether Swift will expand beyond the purview of iOS & OS X development, such as for systems or web scripting, and how that would fundamentally change the role of Cocoa as a de facto standard library.


Thinking Further

Perhaps we’re thinking too small about what a standard library can be.

The Wolfram Language has The Mother of All Demos (with apologies to Douglas Engelbart) for a programming language.

Granted, Wolfram is a parallel universe of computation where nothing else exists, and the language itself is a hot mess.

Here’s an overview of the functionality offered in its standard library:

2D / 3D VisualizationGraph AnalysisData AnalyticsImage Processing
Audio ProcessingMachine LearningEquation SolvingAlgebraic Computation
Arbitrary PrecisionCalculus ComputationMatrix ComputationString Manipulation
Combinatorial OptimizationComputational GeometryDatabase ConnectivityBuilt-In Testing
Device ConnectivityFunctional ProgrammingNatural Language UnderstandingSequence Analysis
Time SeriesGeographic DataGeomappingWeather Data
Physics & Chemistry DataGenomic DataUnits & MeasuresControl Theory
Reliability AnalysisParallel ComputationEngineering DataFinancial Data
Financial ComputationSocioeconomic DataPopular Culture DataBoolean Computation
Number TheoryDocument GenerationTable FormattingMathematical Typesetting
Interactive ControlsInterface BuildingForm ConstructionXML Templating

Conventional wisdom would suggest that, yes: it is unreasonable for a standard library to encode the production budget of the movie Avatar, the max speed of a McDonnell Douglas F/A-18 Hornet, or the shape of France. That is information that can be retrieved by querying IMDB, scraping Wikipedia, and importing from a GIS system.

But other things, like converting miles to kilometers, clustering values, or knowing the size of the Earth—these are things that would be generally useful to a variety of different applications.

Indeed, what sets Cocoa apart from most other standard libraries is all of the specific information it encodes in NSLocale and NSCalendar, but most of this comes from the Unicode Common Locale Data Repository (CLDR).

What’s to stop a standard library from pulling in other data sources? Why not expose an interface to libphonenumber, or expand on what HealthKit is already doing for fundamental units?

Incorporating this kind of data in an organized, meaningful way is too much to expect for a third-party framework, and too important to delegate to the free market of open source.

Yes, in many ways, the question of the role of a standard library is the same as the question of what roles the public and private sectors have in society. Third-Party Libertarians, meet Third-Party Librarytarians.


Swift is compelling not just in terms of what the language itself can do, but what it means to Apple, to iOS & OS X developers, and the developer community at large. There are so many factors in play that questions of technical feasibility cannot be extricated from their social and economic consequences.

Will Swift be released under an open source license? Will Swift unseat Javascript as the only viable web scripting language by adding interpreter to Safari? Ultimately, these will be the kinds of deciding factors for what will become of the Swift Standard Library. If Swift is to become a portable systems and scripting language, it would first need to extricate itself from the Objective-C runtime and a web of heavy dependencies.

What is almost certain, however, is that Cocoa, like Objective-C, is doomed. It’s not as much a question of whether, but when. (And we’re talking years from now; no one is really arguing that Objective-C & Cocoa are going away entirely all at once).

The Swift Standard Library is on a collision course with Cocoa, and if the new language continues to gain momentum, one should expect to see further fracturing and reinvention within the system frameworks.

For 30 years, these technologies have served us well, and the best we can do to honor their contributions is to learn from their mistakes and make sure that what replaces them are insanely great.

Reader Submissions - New Year's 2015

$
0
0

As we take a moment to reflect on our experiences over the past year, one thing is clear: 2014 was an incredible year professionally for Apple developers. So much has happened in such a short timespan, and yet it’s hard to remember our relationship to Objective-C before Swift, or what APIs could have captivated our imagination as much as iOS 8 or WatchKit.

It’s an NSHipster tradition to ask you, dear readers, to send in your favorite tips and tricks from the past year for publication over the New Year’s holiday. This year, with a deluge of new developments—both from Cupertino and the community at large—there were no shortage of interesting tidbits to share.

Thanks to Colin Rofls, Cédric Luthi, Florent Pillet, Heath Borders, Joe Zobkiw, Jon Friskics, Justin Miller, Marcin Matczuk, Mikael Konradsson, Nolan O'Brien, Robert Widmann, Sachin Palewar, Samuel Defago, Sebastian Wittenkamp, Vadim Shpakovski, and Zak Remer for their contributions.


The Secret Lives of Member Functions

From Robert Widmann:

Member functions on Swift classes and structures always have the following type when used statically:

Object -> (Args) -> Thing

For example, you can call reverse() on an array in two ways:

[1,2,3,4].reverse()Array.reverse([1,2,3,4])()

@( ) for Boxing C-Strings

From Samuel Defago:

Given the fact that literals are most of the time associated with numbers and collections, I often forget that they work for UTF8-encoded NULL-terminated C-strings as well, especially when I write code using the runtime:

NSString*propertyAttributesString=@(property_getAttributes(class_getProperty([NSObjectclass],"description")));// T@"NSString",R,C

AmIBeingDebugged

Nolan O'Brien brings the AmIBeingDebugged function to our attention from from this Technical Q&A document:

#include <assert.h>#include <stdbool.h>#include <sys/types.h>#include <unistd.h>#include <sys/sysctl.h>staticBoolAmIBeingDebugged(void){intmib[4];structkinfo_procinfo;size_tsize=sizeof(info);info.kp_proc.p_flag=0;mib[0]=CTL_KERN;mib[1]=KERN_PROC;mib[2]=KERN_PROC_PID;mib[3]=getpid();sysctl(mib,sizeof(mib)/sizeof(*mib),&info,&size,NULL,0);return(info.kp_proc.p_flag&P_TRACED)!=0;}

Use Lazy Variables

From Colin Rofls:

Optionals should be avoided. Implicitly unwrapped optionals should be strongly avoided. Want to declare a var but don’t necessarily have an initial value at init time? Use the lazy keyword, and just don’t call the getter before you have your real value.

lazyvarsomeModelStructure=ExpensiveClass()

If you call set on this var without having ever called the getter, the lazy expression is never evaluated. Great for references to views that you don’t necessarily want to init until viewDidLoad, for instance.

Accessing Child Controllers Inserted Into Storyboard Container Views

From Vadim Shpakovski:

Here is a convenient way to access child controllers inserted into Storyboard container views:

// 1. A property has the same name as a segue identifier in XIB@property(nonatomic)ChildViewController1*childController1;@property(nonatomic)ChildViewController2*childController2;// #pragma mark - UIViewController-(void)prepareForSegue:(UIStoryboardSegue*)seguesender:(id)sender{[superprepareForSegue:seguesender:sender];// 2. All known destination controllers assigned to propertiesif([selfrespondsToSelector:NSSelectorFromString(segue.identifier)]){[selfsetValue:segue.destinationViewControllerforKey:segue.identifier];}}-(void)viewDidLoad{[superviewDidLoad];// 3. Controllers already available bc viewDidLoad is called after prepareForSegueself.childController1.view.backgroundColor=[UIColorredColor];self.childController2.view.backgroundColor=[UIColorblueColor];}

Re-Run without Re-Building

From Heath Borders:

If you’re repeatedly debugging the same problem over and over, you can run your app without rebuilding with “Product > Perform Action > Run without Building” (⌘⌃R).

Quick Access to Playground Resources

From Jon Friskics:

Swift Playgrounds all share the same Shared Playground Data folder that’s symlinked to /Users/HOME/Documents/Shared Playground Data.

If you like using lots of Playgrounds, you’ll want to organize the data that each Playground is using into subfolders of that shared folder, but then you’ve got to let the Playground know where to look. Here’s a helper function that I use that makes that easy:

funcpathToFileInSharedSubfolder(file:String)->String{returnXCPSharedDataDirectoryPath+"/"+NSProcessInfo.processInfo().processName+"/"+file}

That processName property in NSProcessInfo contains the name of the Playground file, so as long as you have already created a sub-folder in the Shared Playground Data folder with the same name you can access those files pretty easily, like reading local JSON:

varjsonReadError:NSError?letjsonData=NSFileManager.defaultManager().contentsAtPath(pathToFileInSharedSubfolder("data.json"))!letjsonArray=NSJSONSerialization.JSONObjectWithData(jsonData,options:nil,error:&jsonReadError)as[AnyObject]

…or pulling out a local image:

letimageView=UIImageView()imageView.image=UIImage(contentsOfFile:pathToFileInSharedSubfolder("image.png"))

The rest of this year’s reader submissions come from Cédric Luthi, who (as in yearspast) contributed a payload of tips and tricks worthy of an entire article unto themselves. Thanks so much for these, Cédric!

CocoaPods, Exposed!

Here’s a quick way to check all the pods used by a (closed source) app:

$ class-dump -C Pods_ /Applications/Squire.app | grep -o "Pods_\w+"

CREATE_INFOPLIST_SECTION_IN_BINARY

Check out the CREATE_INFOPLIST_SECTION_IN_BINARY Xcode setting for command-line apps. It’s much easier to use than the -sectcreate __TEXT __info_plist linker flag and it embeds the processed Info.plist file into the binary.

It’s also a lesson on filing radars. This feature request was filed as rdar://4722772 in 2006 and was addressed about 7 years later.

Stop dylib Hooking

Make hackers' lives tougher with this trick from Sam Marshall:

Add this one line to your “Other Linker Flags”:

-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null

NSBundle -preferredLocalizations

Sometimes, you need to know which language your app is running in. Often, people will use NSLocale +preferredLanguages. Unfortunately this tells nothing about the language the app is actually displaying. It will just give you the ordered list as found in “Settings → General → Language & Region → Preferred Language” Order on iOS, or “System Preferences → Language & Region → Preferred Languages” on OS X.

Imagine that the preferred language order is {English, French} but your app is German only. Calling [[NSLocale preferredLanguages] firstObject] will give you English when you want German.

The proper way to get the actual language used by the app is to use [[NSBundle mainBundle] preferredLocalizations].

From the documentation:

An array of NSString objects containing language IDs for localizations in the bundle. The strings are ordered according to the user’s language preferences and available localizations.

From a comment in NSBundle.h:

A subset of this bundle’s localizations, re-ordered into the preferred order for this process’s current execution environment; the main bundle’s preferred localizations indicate the language (of text) the user is most likely seeing in the UI

You may also need to use NSLocale +canonicalLanguageIdentifierFromString: in order to ensure a canonical language identifier.

Preserve SDK Headers

If you are installing Xcode from the dmg, check out this technique by Joar Wingfors in order to avoid to accidentally modifying SDK headers by preserving ownership, permissions and hard links:

$ sudo ditto /Volumes/Xcode/Xcode.app /Applications/Xcode.app

Inspecting void * Instance Variables

For reverse engineering purpose, it’s often useful to look at instance variables of objects. It’s usually pretty easy to do so with valueForKey:, since very few classes override +accessInstanceVariablesDirectly to disable ivar access through Key-Value Coding.

There’s one case where it doesn’t work though: when the ivar has a void * type.

Here is an excerpt of the MediaPlayer framework class-dump on iOS 6.1:

@interfaceMPMoviePlayerController : NSObject<MPMediaPlayback>{void*_internal;// 4 = 0x4BOOL_readyForDisplay;// 8 = 0x8}

Since id internal = [moviePlayerController valueForKey:@"internal"] doesn’t work, here is the hardcore way to access the internal ivar:

idinternal=*((constid*)(void*)((uintptr_t)moviePlayerController+sizeof(Class)));

Don’t ship this code, its’s very fragile because the ivar layout may change. Use this for reverse engineering only!

NSDateFormatter +dateFormatFromTemplate:options:locale:

A friendly reminder that if you are using NSDateFormatter -setDateFormat: without NSDateFormatter +dateFormatFromTemplate:options:locale:, you’re probably doing it wrong.

From the documentation:

+(NSString*)dateFormatFromTemplate:(NSString*)templateoptions:(NSUInteger)optslocale:(NSLocale*)locale

Different locales have different conventions for the ordering of date components. You use this method to get an appropriate format string for a given set of components for a specified locale (typically you use the current locale—see currentLocale).

The following example shows the difference between the date formats for British and American English:

NSLocale*usLocale=[[NSLocalealloc]initWithLocaleIdentifier:@"en_US"];NSLocale*gbLocale=[[NSLocalealloc]initWithLocaleIdentifier:@"en_GB"];NSString*dateFormat;NSString*dateComponents=@"yMMMMd";dateFormat=[NSDateFormatterdateFormatFromTemplate:dateComponentsoptions:0locale:usLocale];NSLog(@"Date format for %@: %@",[usLocaledisplayNameForKey:NSLocaleIdentifiervalue:[usLocalelocaleIdentifier]],dateFormat);dateFormat=[NSDateFormatterdateFormatFromTemplate:dateComponentsoptions:0locale:gbLocale];NSLog(@"Date format for %@: %@",[gbLocaledisplayNameForKey:NSLocaleIdentifiervalue:[gbLocalelocaleIdentifier]],dateFormat);// Output:// Date format for English (United States): MMMM d, y// Date format for English (United Kingdom): d MMMM y

Deriving Internal Constants with the Debugger

Recently, Matthias Tretter asked on Twitter:

Search for duration in a class-dump of UIKit, find the UITransitionView +defaultDurationForTransition: method, and set a breakpoint for that method:

(lldb) br set -n "+[UITransitionView defaultDurationForTransition:]"

Present a modal view controller, you will hit the breakpoint, type finish to execute the method:

(lldb) finish

At that point defaultDurationForTransition: has executed, and you can read the result (it’s in the xmm0 register):

(lldb) register read xmm0 --format float64
    xmm0 = {0.4 0}

Answer: the default duration is 0.4s.

DIY Weak Associated Objects

Unfortunately, the associated objects OBJC_ASSOCIATION_ASSIGN policy does not support zeroing weak references. Fortunately, it’s quite easy to implement yourself. You just need a simple class to wrap an object with a weak reference:

@interfaceWeakObjectContainter : NSObject@property(nonatomic,readonly,weak)idobject;@end@implementationWeakObjectContainter-(instancetype)initWithObject:(id)object{self=[superinit];if(!self){returnnil;}self.object=object;returnself;}@end

Then, associate the WeakObjectContainter with OBJC_ASSOCIATION_RETAIN(_NONATOMIC):

objc_setAssociatedObject(self,&MyKey,[[WeakObjectContainteralloc]initWithObject:object],OBJC_ASSOCIATION_RETAIN_NONATOMIC);

Use the object property to access it in order to get a zeroing weak reference to the desired object:

idobject=[objc_getAssociatedObject(self,&MyKey)object];

And with that, we bring in a brand new year of possibilities and opportunities. Happy 2015, everyone!

May your code continue to compile and inspire.

Changing of the Guard

$
0
0

I started NSHipster in the summer of 2012. What began as a snarky writing exercise to capture observations from my daily interactions with Cocoa & Objective-C became a full-time passion for learning as much as I could about my craft.

As of today, I am stepping down from my role as managing editor of NSHipster. Nate Cook (@nnnnnnnn) will be taking over ownership and editorial oversight for the site. Nate is a talented engineer and writer who embodies the spirit of curiosity that characterizes NSHipster and its readers. I’m fully confident that he’ll continue to create and cultivate the great content you’ve come to expect every week.

The best is yet to come for NSHipster.

It’s been the thrill of a lifetime to wake up every Monday morning and share a little bit of myself with such an amazing community. I can’t thank you enough for your support, patience, and enthusiasm for me and my work. This was a lot of fun.

May your code continue to compile and inspire.

Long Live Cocoa

$
0
0

It’s the start of a new year—2015, the year of Watch, the first full year for Swift, and a bit of a new start for NSHipster. Before we get caught up in the excitement of new devices and the next beta of Xcode or start planning our trips to WWDC 2015, let’s take a moment to look at our tools as they are today: Objective-C, Swift, and most importantly, Cocoa.

Swift is an exciting language for many of us, but it’s still brand new. The stability of Objective-C and the history and strength of Cocoa mean that Swift isn’t ready to be the driving force behind a major change, at least not quite yet. Cocoa’s depth and the power it affords, along with the way it and Swift go hand in hand, make Cocoa as relevant and as promising as ever. In fact, I don’t think there’s been a more exciting time to be a Cocoa developer.


Cocoa is an impressively deep API—dig a little below the surface of any common tool and you unearth a trove of functionality. You need look no further for proof than the incredible work Mattt has done in these very pages over the last few years, illuminating what we didn’t know Cocoa could do. To name just a few:

The list goes on and on. (Check it out—right there on the front page.)

Hand in Hand

What’s more, Cocoa and Swift are practically—and in Swift’s case, literally—made for each other.

On the Cocoa side, changes to the toolset over the past few years paved the way for Cocoa to be Swift-friendly right out of the gate. Shifting to LLVM/Clang, adding block syntax to Objective-C, pushing the NS_ENUM& NS_OPTIONS macros, converting initializers to return instancetype—all these steps make the Cocoa APIs we’re using today far more compatible with Swift than they could have been even a few years ago. Whenever you supply a Swift closure as a NSURLSession completion handler, or use the suggested completions for UIModalTransitionStyle, you’re building on that work, done years ago when Swift was still behind closed doors (or in Chris Lattner’s head).

Swift was then designed from the ground up to be used with Cocoa. If I could nominate a single Swift feature as most confusing to newcomers, it would be Optionals, with their extra punctuation and unwrapping requirements. Even so, Optionals represent a crowning achievement, one so foundational it fades into the woodwork: Swift is a brand-new language that doesn’t require a brand-new API. It’s a type-safe, memory-safe language whose primary purpose is interacting directly with the enormous C-based Cocoa API, with pointers and raw memory lying all over the place.

This is no small feat. The developer tools team at Apple has been busy annotating the entire API with information about memory management for parameters and return values. Once annotated, functions can be used safely from within Swift, since the compiler knows how to bridge types back and forth from Swift to annotated C code.

Here’s an example of similar annotated and unannotated functions. First, the C versions:

// Creates an immutable copy of a string.CFStringRefCFStringCreateCopy(CFAllocatorRefalloc,CFStringReftheString);// Encodes an OSType into a string suitable for use as a tag argument.CFStringRefUTCreateStringForOSType(OSTypeinOSType);

Both of these functions return a CFStringRef—a reference to a CFString. A CFStringRef can be bridged to a Swift CFString instance, but this is only safe if the method has been annotated. In Swift, you can readily see the difference:

// annotated: returns a memory-managed Swift `CFString`funcCFStringCreateCopy(alloc:CFAllocator!,theString:CFString!)->CFString!// unannotated: returns an *unmanaged* `CFString`funcUTCreateStringForOSType(inOSType:OSType)->Unmanaged<CFString>!

Upon receiving an Unmanaged<CFString>!, you need to follow up with .takeRetainedValue() or .takeUnretainedValue() to get a memory-managed CFString instance. Which to call? To know that, you have to read the documentation or know the conventions governing whether the result you get back is retained or unretained. By annotating these functions, Apple has done that work for you, already guaranteeing memory safety across a huge swath of Cocoa.


Moreover, Swift doesn’t just embrace Cocoa APIs, it actively improves them. Take the venerable CGRect, for example. As a C struct, it can’t contain any instance methods, so all the tools to manipulate CGRects live in top-level functions. These tools are powerful, but you need to know they exist and how to put them to use. These four lines of code, dividing a CGRect into two smaller pieces, might require three trips to the documentation:

CGRectnextRect;CGRectremainingRect;CGRectDivide(sourceRect,&nextRect,&remainingRect,250,CGRectMinXEdge);NSLog("Remaining rect: %@",NSStringFromCGRect(remainingRect));

In Swift, structs happily contain both static and instance methods and computed properties, so Core Graphics extends CGRect to make finding and using those tools far easier. Because CGRect* functions are mapped to instance methods or properties, the code above is reduced to this:

let(nextRect,remainingRect)=sourceRect.rectsByDividing(250,CGRectEdge.MinXEdge)println("Remaining rect: \(remainingRect)")

Getting Better All The Time

To be sure, working with Cocoa and Swift together is sometimes awkward. Where that does happen, it often comes from using patterns that are idiomatic to Objective-C. Delegates, target-selector, and NSInvocation still have their place, but with closures so easy in Swift, it can feel like overkill to add a whole method (or three) just to accomplish something simple. Bringing more closure- or block-based methods to existing Cocoa types can easily smooth out these bumps.

For example, NSTimer has a perfectly fine interface, but it suffers from requiring an Objective-C method to call, either via target-selector or invocation. When defining a timer, chances are I already have everything ready to go. With a simple NSTimer extension using its toll-free bridged Core Foundation counterpart, CFTimer, we’re in business in no time:

letmessage="Are we there yet?"letalert=UIAlertController(title:message,message:nil,preferredStyle:.Alert)alert.addAction(UIAlertAction(title:"No",style:.Default,handler:nil))NSTimer.scheduledTimerWithTimeInterval(10,repeats:true){[weakself]timerinifself?.presentedViewController==nil{self?.presentViewController(alert,animated:true,completion:nil)}}// I swear I'll turn this car around.

None of this is to refute Mattt’s last post, though—on an infinite time scale, we’ll surely be coding against Cocoa’s successor on our 42" iPads while looking out across the Titan moonscape. But as long as Cocoa’s still around, isn’t it great?

JavaScriptCore

$
0
0

An updated ranking of programming language popularity is out this week, showing Swift leaping upward through the ranks from 68th to 22nd, while Objective-C holds a strong lead up ahead at #10. Both, however, are blown away by the only other language allowed to run natively on iOS: the current champion, JavaScript.

Introduced with OS X Mavericks and iOS 7, the JavaScriptCore framework puts an Objective-C wrapper around WebKit’s JavaScript engine, providing easy, fast, and safe access to the world’s most prevalent language. Love it or hate it, JavaScript’s ubiquity has led to an explosion of developers, tools, and resources along with ultra-fast virtual machines like the one built into OS X and iOS.

So come, lay aside bitter debates about dynamism and type safety, and join me for a tour of JavaScriptCore.


JSContext / JSValue

JSContext is an environment for running JavaScript code. A JSContext instance represents the global object in the environment—if you’ve written JavaScript that runs in a browser, JSContext is analogous to window. After creating a JSContext, it’s easy to run JavaScript code that creates variables, does calculations, or even defines functions:

letcontext=JSContext()context.evaluateScript("var num = 5 + 5")context.evaluateScript("var names = ['Grace', 'Ada', 'Margaret']")context.evaluateScript("var triple = function(value) { return value * 3 }")lettripleNum:JSValue=context.evaluateScript("triple(num)")
JSContext*context=[[JSContextalloc]init];[contextevaluateScript:@"var num = 5 + 5"];[contextevaluateScript:@"var names = ['Grace', 'Ada', 'Margaret']"];[contextevaluateScript:@"var triple = function(value) { return value * 3 }"];JSValue*tripleNum=[contextevaluateScript:@"triple(num)"];

As that last line shows, any value that comes out of a JSContext is wrapped in a JSValue object. A language as dynamic as JavaScript requires a dynamic type, so JSValue wraps every possible kind of JavaScript value: strings and numbers; arrays, objects, and functions; even errors and the special JavaScript values null and undefined.

JSValue includes a host of methods for accessing its underlying value as the correct Foundation type, including:

JavaScript TypeJSValue methodObjective-C TypeSwift Type
stringtoStringNSStringString!
booleantoBoolBOOLBool
numbertoNumber
toDouble
toInt32
toUInt32
NSNumber
double
int32_t
uint32_t
NSNumber!
Double
Int32
UInt32
DatetoDateNSDateNSDate!
ArraytoArrayNSArray[AnyObject]!
ObjecttoDictionaryNSDictionary[NSObject : AnyObject]!
ObjecttoObject
toObjectOfClass:
custom typecustom type

To retrieve the value of tripleNum from the above example, simply use the appropriate method:

print("Tripled: \(tripleNum.toInt32())")// Tripled: 30
NSLog(@"Tripled: %d",[tripleNumtoInt32]);// Tripled: 30

Subscripting Values

We can easily access any values we’ve created in our context using subscript notation on both JSContext and JSValue instances. JSContext requires a string subscript, while JSValue allows either string or integer subscripts for delving down into objects and arrays:

letnames=context.objectForKeyedSubscript("names")letinitialName=names.objectAtIndexedSubscript(0)print("The first name: \(initialName.toString())")// The first name: Grace
JSValue*names=context[@"names"];JSValue*initialName=names[0];NSLog(@"The first name: %@",[initialNametoString]);// The first name: Grace

Swift shows its youth, here—while Objective-C code can take advantage of subscript notation, Swift currently only exposes the raw methods that should make such subscripting possible: objectForKeyedSubscript() and objectAtIndexedSubscript().

Calling Functions

With a JSValue that wraps a JavaScript function, we can call that function directly from our Objective-C/Swift code using Foundation types as parameters. Once again, JavaScriptCore handles the bridging without any trouble:

lettripleFunction=context.objectForKeyedSubscript("triple")letresult=tripleFunction.callWithArguments([5])print("Five tripled: \(result.toInt32())")
JSValue*tripleFunction=context[@"triple"];JSValue*result=[tripleFunctioncallWithArguments:@[@5]];NSLog(@"Five tripled: %d",[resulttoInt32]);

Exception Handling

JSContext has another useful trick up its sleeve: by setting the context’s exceptionHandler property, you can observe and log syntax, type, and runtime errors as they happen. exceptionHandler is a callback handler that receives a reference to the JSContext and the exception itself:

context.exceptionHandler={context,exceptioninprint("JS Error: \(exception)")}context.evaluateScript("function multiply(value1, value2) { return value1 * value2 ")// JS Error: SyntaxError: Unexpected end of script
context.exceptionHandler=^(JSContext*context,JSValue*exception){NSLog(@"JS Error: %@",exception);};[contextevaluateScript:@"function multiply(value1, value2) { return value1 * value2 "];// JS Error: SyntaxError: Unexpected end of script

JavaScript Calling

Now we know how to extract values from a JavaScript environment and call functions defined therein. What about the reverse? How can we get access to our custom objects and methods, defined in Objective-C or Swift, from within the JavaScript realm?

There are two main ways of giving a JSContext access to our native client code: blocks and the JSExport protocol.

Blocks

When an Objective-C block is assigned to an identifier in a JSContext, JavaScriptCore automatically wraps the block in a JavaScript function. This makes it simple to use Foundation and Cocoa classes from within JavaScript—again, all the bridging happens for you. Witness the full power of Foundation string transformations, now accessible to JavaScript:

letsimplifyString:@convention(block)String->String={inputinletresult=input.stringByApplyingTransform(NSStringTransformToLatin,reverse:false)returnresult?.stringByApplyingTransform(NSStringTransformStripCombiningMarks,reverse:false)??""}context.setObject(unsafeBitCast(simplifyString,AnyObject.self),forKeyedSubscript:"simplifyString")print(context.evaluateScript("simplifyString('안녕하새요!')"))// annyeonghasaeyo!
context[@"simplifyString"]=^(NSString*input){NSMutableString*mutableString=[inputmutableCopy];CFStringTransform((__bridgeCFMutableStringRef)mutableString,NULL,kCFStringTransformToLatin,NO);CFStringTransform((__bridgeCFMutableStringRef)mutableString,NULL,kCFStringTransformStripCombiningMarks,NO);returnmutableString;};NSLog(@"%@",[contextevaluateScript:@"simplifyString('안녕하세요!')"]);

There’s another speedbump for Swift here—note that this only works for Objective-C blocks, not Swift closures. To use a Swift closure in a JSContext, it needs to be (a) declared with the @convention(block) attribute, and (b) cast to AnyObject using Swift’s knuckle-whitening unsafeBitCast() function.

Memory Management

Since blocks can capture references to variables and JSContexts maintain strong references to all their variables, some care needs to be taken to avoid strong reference cycles. Avoid capturing your JSContext or any JSValues inside a block. Instead, use [JSContext currentContext] to get the current context and pass any values you need as parameters.

JSExport Protocol

Another way to use our custom objects from within JavaScript code is to add conformance to the JSExport protocol. Whatever properties, instance methods, and class methods we declare in our JSExport-inherited protocol will automatically be available to any JavaScript code. We’ll see how in the following section.

JavaScriptCore in Practice

Let’s build out an example that will use all these different techniques—we’ll define a Person model that conforms to the JSExport sub-protocol PersonJSExports, then use JavaScript to create and populate instances from a JSON file. Who needs NSJSONSerialization when there’s an entire JavaScript VM lying around?

1) PersonJSExports and Person

Our Person class implements the PersonJSExports protocol, which specifies what properties should be available in JavaScript.

The create... class method is necessary because JavaScriptCore does not bridge initializers—we can’t simply say var person = new Person() the way we would with a native JavaScript type.

// Custom protocol must be declared with `@objc`@objcprotocolPersonJSExports:JSExport{varfirstName:String{getset}varlastName:String{getset}varbirthYear:NSNumber?{getset}funcgetFullName()->String/// create and return a new Person instance with `firstName` and `lastName`staticfunccreateWithFirstName(firstName:String,lastName:String)->Person}// Custom class must inherit from `NSObject`@objcclassPerson:NSObject,PersonJSExports{// properties must be declared as `dynamic`dynamicvarfirstName:StringdynamicvarlastName:StringdynamicvarbirthYear:NSNumber?init(firstName:String,lastName:String){self.firstName=firstNameself.lastName=lastName}classfunccreateWithFirstName(firstName:String,lastName:String)->Person{returnPerson(firstName:firstName,lastName:lastName)}funcgetFullName()->String{return"\(firstName) \(lastName)"}}
// in Person.h -----------------@classPerson;@protocolPersonJSExports<JSExport>@property(nonatomic,copy)NSString*firstName;@property(nonatomic,copy)NSString*lastName;@propertyNSIntegerageToday;-(NSString*)getFullName;// create and return a new Person instance with `firstName` and `lastName`+(instancetype)createWithFirstName:(NSString*)firstNamelastName:(NSString*)lastName;@end@interfacePerson : NSObject<PersonJSExports>@property(nonatomic,copy)NSString*firstName;@property(nonatomic,copy)NSString*lastName;@propertyNSIntegerageToday;@end// in Person.m -----------------@implementationPerson-(NSString*)getFullName{return[NSStringstringWithFormat:@"%@ %@",self.firstName,self.lastName];}+(instancetype)createWithFirstName:(NSString*)firstNamelastName:(NSString*)lastName{Person*person=[[Personalloc]init];person.firstName=firstName;person.lastName=lastName;returnperson;}@end

2) JSContext Configuration

Before we can use the Person class we’ve created, we need to export it to the JavaScript environment. We’ll also take this moment to import the Mustache JS library, which we’ll use to apply templates to our Person objects later.

// export Person classcontext.setObject(Person.self,forKeyedSubscript:"Person")// load Mustache.jsifletmustacheJSString=String(contentsOfFile:...,encoding:NSUTF8StringEncoding,error:nil){context.evaluateScript(mustacheJSString)}
// export Person classcontext[@"Person"]=[Personclass];// load Mustache.jsNSString*mustacheJSString=[NSStringstringWithContentsOfFile:...encoding:NSUTF8StringEncodingerror:nil];[contextevaluateScript:mustacheJSString];

3) JavaScript Data & Processing

Here’s a look at our simple JSON example and the code that will process it to create new Person instances.

Note: JavaScriptCore translates Objective-C/Swift method names to be JavaScript-compatible. Since JavaScript doesn’t have named parameters, any external parameter names are converted to camel-case and appended to the function name. In this example, the Objective-C method createWithFirstName:lastName: becomes createWithFirstNameLastName() in JavaScript.

varloadPeopleFromJSON=function(jsonString){vardata=JSON.parse(jsonString);varpeople=[];for(i=0;i<data.length;i++){varperson=Person.createWithFirstNameLastName(data[i].first,data[i].last);person.birthYear=data[i].year;people.push(person);}returnpeople;}
[{"first":"Grace","last":"Hopper","year":1906},{"first":"Ada","last":"Lovelace","year":1815},{"first":"Margaret","last":"Hamilton","year":1936}]

4) Tying It All Together

All that remains is to load the JSON data, call into the JSContext to parse the data into an array of Person objects, and render each Person using a Mustache template:

// get JSON stringletpeopleJSON=try!String(contentsOfFile:...,encoding:NSUTF8StringEncoding)// get load functionletload=context.objectForKeyedSubscript("loadPeopleFromJSON")// call with JSON and convert to an Arrayifletpeople=load.callWithArguments([peopleJSON]).toArray()as?[Person]{// get rendering function and create templateletmustacheRender=context.objectForKeyedSubscript("Mustache").objectForKeyedSubscript("render")lettemplate="{{getFullName}}, born {{birthYear}}"// loop through people and render Person object as stringforpersoninpeople{print(mustacheRender.callWithArguments([template,person]))}}// Output:// Grace Hopper, born 1906// Ada Lovelace, born 1815// Margaret Hamilton, born 1936
// get JSON stringNSString*peopleJSON=[NSStringstringWithContentsOfFile:...encoding:NSUTF8StringEncodingerror:nil];// get load functionJSValue*load=context[@"loadPeopleFromJSON"];// call with JSON and convert to an NSArrayJSValue*loadResult=[loadcallWithArguments:@[peopleJSON]];NSArray*people=[loadResulttoArray];// get rendering function and create templateJSValue*mustacheRender=context[@"Mustache"][@"render"];NSString*template=@"{{getFullName}}, born {{birthYear}}";// loop through people and render Person object as stringfor(Person*personinpeople){NSLog(@"%@",[mustacheRendercallWithArguments:@[template,person]]);}// Output:// Grace Hopper, born 1906// Ada Lovelace, born 1815// Margaret Hamilton, born 1936

How can you use JavaScript in your apps? JavaScript snippets could be the basis for user-defined plugins that ship alongside yours. If your product started out on the web, you may have existing infrastructure that can be used with only minor changes. Or if you started out as a programmer on the web, you might relish the chance to get back to your scripty roots. Whatever the case, JavaScriptCore is too well-built and powerful to ignore.

Swift & the Objective-C Runtime

$
0
0

Even when written without a single line of Objective-C code, every Swift app executes inside the Objective-C runtime, opening up a world of dynamic dispatch and associated runtime manipulation. To be sure, this may not always be the case—Swift-only frameworks, whenever they come, may lead to a Swift-only runtime. But as long as the Objective-C runtime is with us, let’s use it to its fullest potential.

This week we take a new, Swift-focused look at two runtime techniques covered on NSHipster back when Objective-C was the only game in town: associated objects and method swizzling.

Note: This post primarily covers the use of these techniques in Swift—for the full run-down, please refer to the original articles.

Associated Objects

Swift extensions allow for great flexibility in adding to the functionality of existing Cocoa classes, but they’re limited in the same way as their Objective-C brethren, categories. Namely, you can’t add a property to an existing class via an extension.

Happily, Objective-C associated objects come to the rescue. For example, to add a descriptiveName property to all the view controllers in a project, we simply add a computed property using objc_get/setAssociatedObject() in the backing get and set blocks:

extensionUIViewController{privatestructAssociatedKeys{staticvarDescriptiveName="nsh_DescriptiveName"}vardescriptiveName:String?{get{returnobjc_getAssociatedObject(self,&AssociatedKeys.DescriptiveName)as?String}set{ifletnewValue=newValue{objc_setAssociatedObject(self,&AssociatedKeys.DescriptiveName,newValueasNSString?,.OBJC_ASSOCIATION_RETAIN_NONATOMIC)}}}}

Note the use of static var in a private nested struct—this pattern creates the static associated object key we need but doesn’t muck up the global namespace.

Method Swizzling

Sometimes for convenience, sometimes to work around a bug in a framework, or sometimes because there’s just no other way, you need to modify the behavior of an existing class’s methods. Method swizzling lets you swap the implementations of two methods, essentially overriding an existing method with your own while keeping the original around.

In this example, we swizzle UIViewController’s viewWillAppear method to print a message any time a view is about to appear on screen. The swizzling happens in the special class method initialize (see note below); the replacement implementation is in the nsh_viewWillAppear method:

extensionUIViewController{publicoverrideclassfuncinitialize(){structStatic{staticvartoken:dispatch_once_t=0}// make sure this isn't a subclassifself!==UIViewController.self{return}dispatch_once(&Static.token){letoriginalSelector=Selector("viewWillAppear:")letswizzledSelector=Selector("nsh_viewWillAppear:")letoriginalMethod=class_getInstanceMethod(self,originalSelector)letswizzledMethod=class_getInstanceMethod(self,swizzledSelector)letdidAddMethod=class_addMethod(self,originalSelector,method_getImplementation(swizzledMethod),method_getTypeEncoding(swizzledMethod))ifdidAddMethod{class_replaceMethod(self,swizzledSelector,method_getImplementation(originalMethod),method_getTypeEncoding(originalMethod))}else{method_exchangeImplementations(originalMethod,swizzledMethod)}}}// MARK: - Method Swizzlingfuncnsh_viewWillAppear(animated:Bool){self.nsh_viewWillAppear(animated)ifletname=self.descriptiveName{print("viewWillAppear: \(name)")}else{print("viewWillAppear: \(self)")}}}

load vs. initialize (Swift Edition)

The Objective-C runtime typically calls two class methods automatically when loading and initializing classes in your app’s process: load and initialize. In the full article on method swizzling, Mattt writes that swizzling should always be done in load(), for safety and consistency. load is called only once per class and is called on each class that is loaded. On the other hand, a single initialize method can be called on a class and all its subclasses, which are likely to exist for UIViewController, or not called at all if that particular class isn’t ever messaged.

Unfortunately, a load class method implemented in Swift is never called by the runtime, rendering that recommendation an impossibility. Instead, we’re left to pick among second-choice options:

  • Implement method swizzling in initialize
    This can be done safely, so long as you check the type at execution time and wrap the swizzling in dispatch_once (which you should be doing anyway).

  • Implement method swizzling in the app delegate
    Instead of adding method swizzling via a class extension, simply add a method to the app delegate to be executed when application(_:didFinishLaunchingWithOptions:) is called. Depending on the classes you’re modifying, this may be sufficient and should guarantee your code is executed every time.


In closing, remember that tinkering with the Objective-C runtime should be much more of a last resort than a place to start. Modifying the frameworks that your code is based upon, as well as any third-party code you run, is a quick way to destabilize the whole stack. Tread softly!

IBInspectable / IBDesignable

$
0
0

Show, don’t tell. Seeing is believing. A picture is worth a thousand emails words.

Whatever the cliché, replacing an interface that requires us to memorize and type with one we can see and manipulate can be an enormous improvement. Xcode 6 makes just such a substitution, building new interactions on top of old technologies. With IBInspectable and IBDesignable, it’s possible to build a custom interface for configuring your custom controls and have them rendered in real-time while designing your project.

IBInspectable

IBInspectable properties provide new access to an old feature: user-defined runtime attributes. Currently accessible from the identity inspector, these attributes have been available since before Interface Builder was integrated into Xcode. They provide a powerful mechanism for configuring any key-value coded property of an instance in a NIB, XIB, or storyboard:

User-Defined Runtime Attributes

While powerful, runtime attributes can be cumbersome to work with. The key path, type, and value of an attribute need to be set on each instance, without any autocompletion or type hinting, which requires trips to the documentation or a custom subclass’s source code to double-check the settings. IBInspectable properties solve this problem outright: in Xcode 6 you can now specify any property as inspectable and get a user interface built just for your custom class.

For example, these properties in a UIView subclass update the backing layer with their values:

@IBInspectablevarcornerRadius:CGFloat=0{didSet{layer.cornerRadius=cornerRadiuslayer.masksToBounds=cornerRadius>0}}@IBInspectablevarborderWidth:CGFloat=0{didSet{layer.borderWidth=borderWidth}}@IBInspectablevarborderColor:UIColor?{didSet{layer.borderColor=borderColor?.CGColor}}

Marked with @IBInspectable (or IBInspectable in Objective-C), they are easily editable in Interface Builder’s inspector panel. Note that Xcode goes the extra mile here—property names are converted from camel- to title-case and related names are grouped together:

IBInspectable Attribute Inspector

Since inspectable properties are simply an interface on top of user-defined runtime attributes, the same list of types is supported: booleans, strings, and numbers (i.e., NSNumber or any of the numeric value types), as well as CGPoint, CGSize, CGRect, UIColor, and NSRange, adding UIImage for good measure.

Those already familiar with runtime attributes will have noticed a bit of trickery in the example above. UIColor is the only color type supported, not the CGColor native to a view’s backing CALayer. The borderColor computed property maps the UIColor (set via runtime attribute) to the layer’s required CGColor.

Making Existing Types Inspectable

Built-in Cocoa types can also be extended to have inspectable properties beyond the ones already in Interface Builder’s attribute inspector. If you like rounded corners, you’ll love this UIView extension:

extensionUIView{@IBInspectablevarcornerRadius:CGFloat{get{returnlayer.cornerRadius}set{layer.cornerRadius=newValuelayer.masksToBounds=newValue>0}}}

Presto! A configurable border radius on any UIView you create.

IBDesignable

As if that weren’t enough, IBDesignable custom views also debut in Xcode 6. When applied to a UIView or NSView subclass, the @IBDesignable designation lets Interface Builder know that it should render the view directly in the canvas. This allows seeing how your custom views will appear without building and running your app after each change.

To mark a custom view as IBDesignable, prefix the class name with @IBDesignable (or the IB_DESIGNABLE macro in Objective-C). Your initializers, layout, and drawing methods will be used to render your custom view right on the canvas:

@IBDesignableclassMyCustomView:UIView{...}

IBDesignable Live Preview

The time-savings from this feature can’t be overstated. Combined with IBInspectable properties, a designer or developer can easily tweak the rendering of a custom control to get the exact result she wants. Any changes, whether made in code or the attribute inspector, are immediately rendered on the canvas.

Moreover, any problems can be debugged without compiling and running the whole project. To kick off a debugging session right in place, simply set a breakpoint in your code, select the view in Interface Builder, and choose EditorDebug Selected Views.

Since the custom view won’t have the full context of your app when rendered in Interface Builder, you may need to generate mock data for display, such as a default user profile image or generic weather data. There are two ways to add code for this special context:

  • prepareForInterfaceBuilder(): This method compiles with the rest of your code but is only executed when your view is being prepared for display in Interface Builder.

  • TARGET_INTERFACE_BUILDER: The #if TARGET_INTERFACE_BUILDER preprocessor macro will work in either Objective-C or Swift to conditionally compile the right code for the situation:

#if !TARGET_INTERFACE_BUILDER// this code will run in the app itself#else// this code will execute only in IB#endif

IBCalculatorConstructorSet

What can you create with a combination of IBInspectable attributes in your IBDesignable custom view? As an example, let’s update an old classic from Apple folklore: the “Steve Jobs Roll Your Own Calculator Construction Set,” Xcode 6-style (gist):

Calculator Construction Set



That was almost a thousand words—let’s see some more pictures. What are you creating with these powerful new tools? Tweet an image of your IBInspectable or IBDesignable creations with the hashtag #IBInspectable—we can all learn from seeing what’s possible.


Swift 1.2

$
0
0

Swift, true to its name, is moving fast. This week marks the beta release of Swift 1.2, a major update to the language. The Swift team has responded to so many of the community’s requests in one fell swoop, we’re overflowing with new and exciting features. Every line-item in this announcement is a big advancement: incremental builds, improved error messages and stability in Xcode, static class properties, support for C unions and bitfields, bridging of Swift enums to Objective-C, safer type casting, improvements to single-line closures, and more.

In what follows, let’s look at two major aspects of the release that will significantly improve the experience of working in Swift: first, big changes in if let optional binding (“finally”), and second, new access to nullability annotations in Objective-C.

Improved Optional Binding

Swift 1.2 allows multiple simultaneous optional bindings, providing an escape from the trap of needing deeply nested if let statements to unwrap multiple values. Multiple optional bindings are separated by commas and can be paired with a where clause that acts like the expression in a traditional if statement. As such, the byzantine pyramid of doom has been renovated into a mid-century modern ranch:

Old:

leta="10".toInt()letb="5".toInt()letc="3".toInt()ifleta=a{ifletb=b{ifletc=c{ifc!=0{println("(a + b) / c = \((a + b) / c)")}}}}

New:

ifleta=a,b=b,c=cwherec!=0{println("(a + b) / c = \((a + b) / c)")// (a + b) / c = 5}

The order of execution in these two examples is identical. Using the new syntax, each binding is evaluated in turn, stopping if any of the attempted bindings is nil. Only after all the optional bindings are successful is the where clause checked.

An if statement can actually have more than one let binding separated by commas. Since each let binding can bind multiple optionals and include a where clause, some truly sophisticated logic is possible with this construct. (Thanks to Stephen Celis for helping clarify this point.)

What’s more, later binding expressions can reference earlier bindings. This means you can delve into Dictionary instances or cast an AnyObject? value to a specific type, then use it in another expression, all in a single if let statement.

To revisit the canonical example, this is what parsing a big block of JSON can look like in Swift 1.2. The example uses one if let block to handle the optionals that come with using NSBundle, NSURL and NSData, then another to map several AnyObject? instances from the interpreted JSON to specific types:

varusers:[User]=[]// load and parse the JSON into an arrayifletpath=NSBundle.mainBundle().pathForResource("users",ofType:"json"),url=NSURL(fileURLWithPath:path),data=NSData(contentsOfURL:url),userList=NSJSONSerialization.JSONObjectWithData(data,options:nil,error:nil)as?[[String:AnyObject]]{// extract individual usersforuserDictinuserList{ifletid=userDict["id"]as?Int,name=userDict["name"]as?String,email=userDict["email"]as?String,address=userDict["address"]as?[String:AnyObject]{users.append(User(id:id,name:name,...))}}}
[{"id":1,"name":"Leanne Graham","username":"Bret","email":"Sincere@april.biz","address":{"street":"Kulas Light","suite":"Apt. 556","city":"Gwenborough","zipcode":"92998-3874","geo":{"lat":"-37.3159","lng":"81.1496"}},"phone":"1-770-736-8031 x56442","website":"hildegard.org","company":{"name":"Romaguera-Crona","catchPhrase":"Multi-layered client-server neural-net","bs":"harness real-time e-markets"}},{"id":2,"name":"Ervin Howell","username":"Antonette","email":"Shanna@melissa.tv","address":{"street":"Victor Plains","suite":"Suite 879","city":"Wisokyburgh","zipcode":"90566-7771","geo":{"lat":"-43.9509","lng":"-34.4618"}},"phone":"010-692-6593 x09125","website":"anastasia.net","company":{"name":"Deckow-Crist","catchPhrase":"Proactive didactic contingency","bs":"synergize scalable supply-chains"}},...]

I see many commas in our future.

Nullability Annotations

When Swift was first released, every call to a Cocoa API method took and returned implicitly unwrapped optionals (i.e., AnyObject!). Because they crash a program on access, implicitly unwrapped return values are inherently unsafe if there isn’t clear documentation of whether or not a method will return a null value. All those exclamation marks were a sign of bad form. Sure, Swift bridged to the Cocoa APIs, but it always looked grumpy about it.

As the beta releases rolled on through the summer and fall, internal audits gradually removed the offending punctuation, replacing implicitly unwrapped optionals with either true optionals or non-optional, never-gonna-be-nil values. This vastly improved the experience of working with Cocoa, but there was no mechanism to mark up third-party code in the same way, leaving part of the problem in place.

But no longer—Swift 1.2 ships alongside a new version of Clang. New property attributes and pointer annotations allow you to indicate whether a pointer, be it an Objective-C property, method parameter, or return value, can or won’t ever be nil.

  • nonnull: Indicates that the pointer should/will never be nil. Pointers annotated with nonnull are imported into Swift as their non-optional base value (i.e., NSData).
  • nullable: Indicates that the pointer can be nil in general practice. Imported into Swift as an optional value (NSURL?).
  • null_unspecified: Continues the current functionality of importing into Swift as an implicitly unwrapped optional, ideally to be used during this annotation process only.
  • null_resettable: Indicates that while a property will always have a value, it can be reset by assigning nil. Properties with a non-nil default value can be annotated this way, like tintColor. Imported into Swift as a (relatively safe) implicitly unwrapped optional. Document accordingly!

The first three annotations can also be used with C pointers and block pointers, using the doubly-underscored __nonnull, __nullable, and __null_unspecified. The last annotation, null_resettable, is only valid as an Objective-C property attribute.

Nullability in Action

As an example to show the benefit of these annotations, let’s take a look at a data controller used to handle a list of locations, each with a possible attached photo:

@interfaceLocationDataController : NSObject@property(nonatomic,readonly)NSArray*locations;@property(nonatomic,readonly)Location*latestLocation;-(void)addPhoto:(Photo*)photoforLocation:(Location*)location;-(Photo*)photoForLocation:(Location*)location;@end

Without any nullability annotations, each pointer in my LocationDataController class is imported to Swift as an implicitly unwrapped optional:

classLocationDataController:NSObject{varlocations:[AnyObject]!{get}varlatestLocation:Location!{get}funcaddPhoto(photo:Photo!,forLocationlocation:Location!)funcphotoForLocation(location:Location!)->Photo!}

Enough! With! The shouting! Here’s how I can now annotate the Objective-C interface:

@interfaceLocationDataController : NSObject@property(nonnull,nonatomic,readonly)NSArray*locations;@property(nullable,nonatomic,readonly)Location*latestLocation;-(void)addPhoto:(nonnullPhoto*)photoforLocation:(nonnullLocation*)location;-(nullablePhoto*)photoForLocation:(nonnullLocation*)location;@end

First, the properties—my locations list is nonnull, since at worst it will be an empty array, but latestLocationcan be nil if there are no locations in the list yet. Likewise, the parameters to my two methods should always have a value, yet because not all locations have a photo, that second method returns a nullable photo. Back in Swift, the results are much better—that is, clearer about how to safely use the data controller and no more grumpy !s:

classLocationDataController:NSObject{varlocations:[AnyObject]{get}varlatestLocation:Location?{get}funcaddPhoto(photo:Photo,forLocationlocation:Location)funcphotoForLocation(location:Location)->Photo?}

NS_ASSUME_NONNULL_BEGIN/END

Annotating any pointer in an Objective-C header file causes the compiler to expect annotations for the entire file, bringing on a cascade of warnings. Given that most annotations will be nonnull, a new macro can help streamline the process of annotating existing classes. Simply mark the beginning and end of a section of your header with NS_ASSUME_NONNULL_BEGIN and ..._END, then mark the exceptions.

Another revision of our data controller interface from above results in a more readable version with the exact same Swift profile:

@interfaceLocationDataController : NSObjectNS_ASSUME_NONNULL_BEGIN@property(nonatomic,readonly)NSArray*locations;@property(nullable,nonatomic,readonly)Location*latestLocation;-(void)addPhoto:(Photo*)photoforLocation:(Location*)location;-(nullablePhoto*)photoForLocation:(Location*)location;NS_ASSUME_NONNULL_END@end

Not Just for Swift

The new Objective-C nullability annotations have huge benefits for code on the Swift side of the fence, but there’s a substantial gain here even without writing a line of Swift. Pointers marked as nonnull will now give a hint during autocomplete and yield a warning if sent nil instead of a proper pointer:

// Can I remove a photo by sending nil?[dataControlleraddPhoto:nilforLocation:currentLocation];// Nope -- Warning: Null passed to a callee that requires a non-null argument

Excitingly, all that is just half the story. In addition to the changes in Swift syntax and compiler savoir faire, the standard library has also seen a major revision, including a proper Set class (so long, dear friend). Okaaay, so none of our code works anymore, and Stack Overflow has 21,000 out-of-date Swift questions? It’s still fun to be along for the ride.

Swift Collection Protocols

$
0
0

Swift has a well-designed and expansive suite of built-in collection types. Beyond Array, Dictionary, and the brand new Set types, the standard library provides slices, lazy collections, repeated sequences, and more, all with a consistent interface and syntax for operations. A group of built-in collection protocols—SequenceType, CollectionType, and several others—act like the steps on a ladder. With each step up, a collection type gains more functionality within the language and the standard library.

By conforming to these protocols, custom collection types can gain access to the same language constructs and powerful top-level functions we use with Array and Dictionary. This week we’ll explore these protocols: what they are, how to conform to them, and what benefits they can provide for your own custom collection types.


To demonstrate the different protocols, along the way we’ll build a new collection type, SortedCollection, which keeps its elements in ascending order for simple, always-sorted access. The implementation shown here is deliberately kept minimal—you can only create a collection and insert, remove, or find elements:

structSortedCollection<T:Comparable>{privatevarcontents:[T]=[]init<S:SequenceTypewhereS.Generator.Element==T>(_sequence:S){contents=sorted(sequence)}funcindexOf(value:T)->Int?{letindex=_insertionIndex(contents,forValue:value)ifindex>=contents.count{returnnil}returncontents[index]==value?index:nil}mutatingfuncinsert(value:T){contents.insert(value,atIndex:_insertionIndex(contents,forValue:value))}mutatingfuncremove(value:T)->T?{ifletindex=indexOf(value){returncontents.removeAtIndex(index)}returnnil}}// Note: _insertionIndex is a private function that returns the // insertion point for a value in a sorted collection.

A complete implementation of SortedCollectionis available as a framework.

Not too much there! Let’s see what kind of functionality we can add by conforming to a few of Swift’s collection protocols.


SequenceType / GeneratorType

The first two collection protocols are inextricably linked: a sequence (a type that conforms to SequenceType ) represents a series of values, while a generator (conforming to GeneratorType, of course) provides a way to use the values in a sequence, one at a time, in sequential order. The SequenceType protocol only has one requirement: every sequence must provide a generator from its generate() method.

A generator works by providing a single method, namely, next(), which simply returns the next value from the underlying sequence. next() will continue returning values until there are none left (), at which point it will return nil. Note that this may never comes to pass, since sequences aren’t necessarily finite.

Whenever you iterate over a sequence, Swift creates a generator and successively calls its next() method. The familiar code for element in myArray { ... } is in fact just a nice wrapper for this:

vargenerator=myArray.generate()whileletelement=generator.next(){// do something}

The relationship between the two protocols is asymmetrical. That is, every sequence has a generator, but only some generators are themselves also sequences (which they can become by returning themselves from their generate() method). Swift includes a whole host of generators, including one that is perfect for our SortedCollection case: the type-erasing GeneratorOf. GeneratorOf is initialized with either the next method implemented as a closure, or another generator:

extensionSortedCollection:SequenceType{typealiasGenerator=GeneratorOf<T>funcgenerate()->Generator{varindex=0returnGeneratorOf{ifindex<self.contents.count{returnself.contents[index++]}returnnil}}}

Ten lines of code later, we can now use SortedCollection with a dozen or so top-level functions, including the bedrock of the functional approach in Swift—reduce, map, and filter.

  • contains: Returns true if (1) a particular given element is found in the sequence or (2) an element satisfies the given predicate closure.
  • enumerate: Converts a sequence into a sequence of tuples, where each tuple is made up of a zero-based index and the value at that index in the sequence.
  • filter: Converts a sequence to an Array, keeping only the elements that match the given predicate closure.
  • join: Creates a collection from the sequence, with a given initial collection interposed between each element of the sequence. The initial element must be an ExtensibleCollectionType, described below.
  • lazy: Creates a “lazy sequence” from the given sequence. Subsequent calls to map, filter, and reverse on the sequence will be evaluated lazily—that is, until you access or iterate over the sequence, none of the transformations will be executed.
  • map: Converts a sequence to an Array after mapping each element with the transforming closure given.
  • maxElement: Returns the maximum value of a sequence of Comparable elements.
  • minElement: Returns the minimum value of a sequence of Comparable elements.
  • reduce: Given an initial value and a combining closure, this “reduces” a sequence to a single element through repeated calls to the closure.
  • sorted: Returns a sorted Array of the sequence’s elements. Sorting is automatically ascending for sequences of Comparable elements, or it can be based on a comparison closure.
  • startsWith: Returns true if one sequence starts with another sequence.
  • underestimateCount: Returns an underestimate of the number of elements in a sequence (SequenceTypes give no hints about length, so this will be zero for a sequence). Returns the actual count for CollectionType instances.
  • zip: Converts two sequences into a sequence of tuples, where each tuple is made up of one element from each sequence.

CollectionType / MutableCollectionType

A collection (a type that conforms to the next collection protocol, CollectionType) is a step beyond a sequence in that individual elements of a collection can be accessed multiple times via subscript. A type conforms by providing a subscripted getter for elements, then starting and ending index properties. No infinite collections here! A MutableCollectionType adds a setter for the same subscript.

Our SortedCollection can easily use Int for its index, so conforming to CollectionType is straightforward:

extensionSortedCollection:CollectionType{typealiasIndex=IntvarstartIndex:Int{return0}varendIndex:Int{returncount}subscript(i:Int)->T{returncontents[i]}}

Subscripting should always be considered an O(1) operation. Types that can’t provide efficient subscripted lookups should move the time-consuming work to the process of generating.

Swift’s built-in String, for example, lost its Int-based subscripting in an early beta. Why? Strings in Swift are fully Unicode-aware, so each visible character may be made up of multiple codepoints. Jumping to an arbitrary index in a string as if it were just an array of characters could land you in the middle of a multi-codepoint sequence, requiring the slightly cumbersome but intuitively O(n) use of startIndex, endIndex, and advance().

Like SequenceType, there are a host of global functions that can operate on CollectionType instances. Now that the start and end of the collection are known, count, sort, and other finite operations become available as top-level functions:

  • count: Returns the number of elements in a collection.
  • find: Returns the first index of a given element in the collection, or nil if not found.
  • first: Returns the first element in the collection, or nil if the collection is empty.
  • indices: Returns a Range of the collection’s indices. Equivalent to c.startIndex..<c.endIndex.
  • isEmpty: Returns true if the collection has no elements.
  • last: Returns the last element in the collection, or nil if the collection is empty.
  • partition: The primary function used in a quick sort (a fast, memory-efficient sorting algorithm). partition reorders part of a collection and returns a pivot index, where everything below the pivot is equal to or ordered before the pivot, and everything above the pivot is equal to or ordered after. Partitioning can be based on a comparison closure if the collection’s elements themselves are not Comparable. Requires MutableCollectionType.
  • reverse: Returns an Array with the elements of the collection in reverse order.
  • sort: Sorts a collection in place, modifying the order of the existing collection. Requires MutableCollectionType.

Sliceable / MutableSliceable

Next up, Sliceable collections promise efficient slicing of a subrange of a collection’s elements. That is, getting a slice of a collection should not require allocating new memory for the selected elements. Again, the standard library guides us: Array and ContiguousArray are the two Sliceable types (besides, well, Slice), and both share their internal storage with their slices until a mutation occurs. This saves both memory and the time needed to allocate new storage for a temporary slice.

For SortedCollection to conform to Sliceable, we need to fulfill that same promise. Happily, we can reuse our embedded Array’s sliceability in a new SortedSlice type, this time based on a Slice<T> instead of an Array:

extensionSortedCollection:Sliceable{typealiasSubSlice=SortedSlice<T>subscript(range:Range<Int>)->SortedSlice<T>{returnSortedSlice(sortedSlice:contents[range])}}// MARK: - SortedSlicestructSortedSlice<T:Comparable>{privatevarcontents:Slice<T>=[]privateinit(sortedSlice:Slice<T>){self.contents=sortedSlice}...}

For other custom collections, Swift 1.2 provides a ManagedBufferPointer type and an isUniquelyReferenced function to help implement the copy-on-write behavior needed for efficient slicing.

Sliceable’s mutable counterpart, MutableSliceable, allows setting a slice’s new contents via subscripting a range of values. Again, mutating by index doesn’t comport with SortedCollections’s requirement to always maintain ascending order. However, none of the Sliceable-ready top-level functions requires mutability:

  • dropFirst: Returns a slice with all but the first element of the collection.
  • dropLast: Returns a slice with all but the last element of the collection.
  • prefix: Returns a slice with the first x elements of the collection or the whole collection if x is greater than the collection’s count.
  • split: Returns an Array of slices separated by elements that match the given isSeparator closure. Optional parameters: a maximum number of splits; a boolean indicating whether empty slices are allowed when consecutive separators are found.
  • suffix: Returns a slice with the last x elements of the collection or the whole collection if x is greater than the collection’s count.

ExtensibleCollectionType / RangeReplaceableCollectionType

Finally, collections that conform to ExtensibleCollectionType and RangeReplaceableCollectionType provide methods to modify the collection. ExtensibleCollectionType requires an empty initializer and three methods: append and extend, which add a single element and a sequence of elements, respectively, and reserveCapacity, which (hopefully) expands the collection’s internal storage to allow additions to the collection without repeatedly reallocating memory.

RangeReplaceableCollectionType requires six methods that replace or remove a range of elements: replaceRange(:with:), insert(:atIndex:), splice(:atIndex:), removeAtIndex(:), removeRange(:), and removeAll(). Conforming types have access to top-level functions that do largely the same:

  • extend: Appends the elements of a collection to a given range-replaceable collection.
  • insert: Inserts a new element into the collection at a particular index.
  • removeAll: Removes all elements from a collection, optionally preserving the collection’s internal capacity.
  • removeLast: Removes a single element from the end of a collection.
  • removeRange: Removes a range of elements from a collection.
  • splice: Inserts a sequence of elements at a particular index of a range-replaceable collection.

Sorting Out the Oscars

So let’s put all this to (popcultural) use. We haven’t added any methods to SortedCollection other than those required to conform to SequenceType, CollectionType, and Sliceable, but yet we’ve gained access to many powerful top-level functions.

We start with the guest list of an after-party for some of last night’s big winners at the Oscars:

letattendees=SortedCollection(["Julianne","Eddie","Patricia","J.K.","Alejandro"])

How many attendees? Using count:

println("\(count(attendees)) attendees")// 5 attendees

Suppose I’d like the stars to line up alphabetically for a photo—how can I give them instructions? Using zip and dropFirst:

for(firstName,secondName)inzip(attendees,dropFirst(attendees)){println("\(firstName) is before \(secondName)")}// Alejandro is before Eddie// Eddie is before J.K.// J.K. is before Julianne// Julianne is before Patricia

Lastly, I need the names to be reformatted so I can use them as image file names. Using map:

letimageNames=map(attendees){$0.lowercaseString}.map{$0.stringByTrimmingCharactersInSet(NSCharacterSet.alphanumericCharacterSet().invertedSet)}.map{"\($0).jpg"}// alejandro.jpg// eddie.jpg// ...

Voila! A-list party!


Without a doubt, part of what makes Swift so fascinating to use is that the language seems largely self-defined. Browse through the standard library and you can see how each type is built—from Int and Double to Array, Dictionary, and the new Set. With an eye toward building more Swift-native types, follow Swift’s example in creating your own!

NSScanner

$
0
0

Strings are a ubiquitous and diverse part of our computing lives. They comprise emails and essays, poems and novels—and indeed, every article on nshipster.com, the configuration files that shape the site, and the code that builds it.

Being able to pull apart strings and extract particular bits of data is therefore a powerful skill, one that we use over and over building apps and shaping our tools. Cocoa provides a powerful set of tools to handle string processing. In particular:

  • string.componentsSeparatedByCharactersInSet / string.componentsSeparatedByString: Great for splitting a string into constituent pieces. Not so great at anything else.

  • NSRegularExpression: Powerful for validating and extracting string data from an expected format. Cumbersome when dealing with complex serial input and finicky for parsing numeric values.

  • NSDataDetector: Perfect for detecting and extracting dates, addresses, links, and more. Limited to its predefined types.

  • NSScanner: Highly configurable and designed for scanning string and numeric values from loosely demarcated strings.

This week’s article focuses on the last of these, NSScanner. Read on to learn about its flexibility and power.


Among Cocoa’s tools, NSScanner serves as a wrapper around a string, scanning through its contents to efficiently retrieve substrings and numeric values. It offers several properties that modify an NSScanner instance’s behavior:

  • caseSensitiveBool: Whether to pay attention to the upper- or lower-case while scanning. Note that this property only applies to the string-matching methods scanString:intoString: and scanUpToString:intoString:—character sets scanning is always case-sensitive.
  • charactersToBeSkippedNSCharacterSet: The characters to skip over on the way to finding a match for the requested value type.
  • scanLocationInt: The current position of the scanner in its string. Scanning can be rewound or restarted by setting this property.
  • localeNSLocale: The locale that the scanner should use when parsing numeric values (see below).

An NSScanner instance has two additional read-only properties: string, which gives you back the string the scanner is scanning; and atEnd, which is true if scanLocation is at the end of the string.

Note:NSScanner is actually the abstract superclass of a private cluster of scanner implementation classes. Even though you’re calling alloc and init on NSScanner, you’ll actually receive one of these subclasses, such as NSConcreteScanner. No need to fret over this.

Extracting Substrings and Numeric Values

The raison d'être of NSScanner is to pull substrings and numeric values from a larger string. It has fifteen methods to do this, all of which follow the same basic pattern. Each method takes a reference to an output variable as a parameter and returns a boolean value indicating success or failure of the scan:

letwhitespaceAndPunctuationSet=NSMutableCharacterSet.whitespaceAndNewlineCharacterSet()whitespaceAndPunctuationSet.formUnionWithCharacterSet(NSCharacterSet.punctuationCharacterSet())letstringScanner=NSScanner(string:"John & Paul & Ringo & George.")stringScanner.charactersToBeSkipped=whitespaceAndPunctuationSet// using the latest Swift 1.2 beta 2 syntax:varname:NSString?whilestringScanner.scanUpToCharactersFromSet(whitespaceAndPunctuationSet,intoString:&name){println(name)}// John// Paul// Ringo// George
NSMutableCharacterSet*whitespaceAndPunctuationSet=[NSMutableCharacterSetpunctuationCharacterSet];[whitespaceAndPunctuationSetformUnionWithCharacterSet:[NSCharacterSetwhitespaceAndNewlineCharacterSet]];NSScanner*stringScanner=[[NSScanneralloc]initWithString:@"John & Paul & Ringo & George."];stringScanner.charactersToBeSkipped=whitespaceAndPunctuationSet;NSString*name;while([stringScannerscanUpToCharactersFromSet:whitespaceAndPunctuationSetintoString:&name]){NSLog(@"%@",name);}// John// Paul// Ringo// George

The NSScanner API has methods for two use-cases: scanning for strings generally, or for numeric types specifically.

1) String Scanners

scanString:intoString: / scanCharactersFromSet:intoString:
Scans to match the string parameter or characters in the NSCharacterSet parameter, respectively. The intoString parameter will return containing the scanned string, if found. These methods are often used to advance the scanner’s location—pass nil for the intoString parameter to ignore the output.
scanUpToString:intoString: / scanUpToCharactersFromSet:intoString:
Scans characters into a string until finding the string parameter or characters in the NSCharacterSet parameter, respectively. The intoString parameter will return containing the scanned string, if any was found. If the given string or character set are not found, the result will be the entire rest of the scanner’s string.

2) Numeric Scanners

scanDouble: / scanFloat: / scanDecimal:
Scans a floating-point value from the scanner’s string and returns the value in the referenced Double, Float, or NSDecimal instance, if found.
scanInteger: / scanInt: / scanLongLong: / scanUnsignedLongLong:
Scans an integer value from the scanner’s string and returns the value in the referenced Int, Int32, Int64, or UInt64 instance, if found.
scanHexDouble: / scanHexFloat:
Scans a hexadecimal floating-point value from the scanner’s string and returns the value in the referenced Double or Float instance, if found. To scan properly, the floating-point value must have a 0x or 0X prefix.
scanHexInt: / scanHexLongLong:
Scans a hexadecimal integer value from the scanner’s string and returns the value in the referenced UInt32 or UInt64 instance, if found. The value may have a 0x or 0X prefix, but it is not required.

localizedScannerWithString / locale

Because it is a part of Cocoa, NSScanner has built-in localization support (of course). An NSScanner instance can work with either the user’s locale when created via + localizedScannerWithString:, or a specific locale after setting its locale property. In particular, the separator for floating-point values will be correctly interpreted based on the given locale:

varprice=0.0letgasPriceScanner=NSScanner(string:"2.09 per gallon")gasPriceScanner.scanDouble(&price)// 2.09// use a german locale instead of the defaultletbenzinPriceScanner=NSScanner(string:"1,38 pro Liter")benzinPriceScanner.locale=NSLocale(localeIdentifier:"de-DE")benzinPriceScanner.scanDouble(&price)// 1.38
doubleprice;NSScanner*gasPriceScanner=[[NSScanneralloc]initWithString:@"2.09 per gallon"];[gasPriceScannerscanDouble:&price];// 2.09// use a german locale instead of the defaultNSScanner*benzinPriceScanner=[[NSScanneralloc]initWithString:@"1,38 pro Liter"];[benzinPriceScannersetLocale:[NSLocalelocaleWithLocaleIdentifier:@"de-DE"]];[benzinPriceScannerscanDouble:&price];// 1.38

Example: Parsing SVG Path Data

To take NSScanner out for a spin, we’ll look at parsing the path data from an SVG path. SVG path data are stored as a string of instructions for drawing the path, where “M” indicates a “move-to” step, “L” stands for “line-to”, and “C” stands for a curve. Uppercase instructions are followed by points in absolute coordinates; lowercase instructions are followed by coordinates relative to the last point in the path.

Here’s an SVG path I happen to have lying around (and a point-offsetting helper we’ll use later):

varsvgPathData="M28.2,971.4c-10,0.5-19.1,13.3-28.2,2.1c0,15.1,23.7,30.5,39.8,16.3c16,14.1,39.8-1.3,39.8-16.3c-12.5,15.4-25-14.4-39.8,4.5C35.8,972.7,31.9,971.2,28.2,971.4z"extensionCGPoint{funcoffset(p:CGPoint)->CGPoint{returnCGPoint(x:x+p.x,y:y+p.y)}}
staticNSString*constsvgPathData=@"M28.2,971.4c-10,0.5-19.1,13.3-28.2,2.1c0,15.1,23.7,30.5,39.8,16.3c16,14.1,39.8-1.3,39.8-16.3c-12.5,15.4-25-14.4-39.8,4.5C35.8,972.7,31.9,971.2,28.2,971.4z";CGPointoffsetPoint(CGPointp1,CGPointp2){returnCGPointMake(p1.x+p2.x,p1.y+p2.y);}

Note that the point data are fairly irregular. Sometimes the x and y values of a point are separated by a comma, sometimes not, and likewise with points themselves. Parsing these data with regular expressions could turn into a mess pretty quickly, but with NSScanner the code is clear and straightforward.

We’ll define a bezierPathFromSVGPath function that will convert a string of path data into an UIBezierPath. Our scanner is set up to skip commas and whitespace while scanning for values:

funcbezierPathFromSVGPath(str:String)->UIBezierPath{letscanner=NSScanner(string:str)// skip commas and whitespaceletskipChars=NSMutableCharacterSet(charactersInString:",")skipChars.formUnionWithCharacterSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())scanner.charactersToBeSkipped=skipChars// the resulting bezier pathvarpath=UIBezierPath()
-(UIBezierPath*)bezierPathFromSVGPath:(NSString*)str{NSScanner*scanner=[NSScannerscannerWithString:str];// skip commas and whitespaceNSMutableCharacterSet*skipChars=[NSMutableCharacterSetcharacterSetWithCharactersInString:@","];[skipCharsformUnionWithCharacterSet:[NSCharacterSetwhitespaceAndNewlineCharacterSet]];scanner.charactersToBeSkipped=skipChars;// the resulting bezier pathUIBezierPath*path=[UIBezierPathbezierPath];

With the setup out of the way, it’s time to start scanning. We start by scanning for a string made up of characters in the allowed set of instructions:

// instructions code can be upper- or lower-caseletinstructionSet=NSCharacterSet(charactersInString:"MCSQTAmcsqta")varinstruction:NSString?// scan for an instruction codewhilescanner.scanCharactersFromSet(instructionSet,intoString:&instruction){
// instructions codes can be upper- or lower-caseNSCharacterSet*instructionSet=[NSCharacterSetcharacterSetWithCharactersInString:@"MCSQTAmcsqta"];NSString*instruction;// scan for an instruction codewhile([scannerscanCharactersFromSet:instructionSetintoString:&instruction]){

The next section scans for two Double values in a row, converts them to a CGPoint, and then ultimately adds the correct step to the bezier path:

varx=0.0,y=0.0varpoints:[CGPoint]=[]// scan for pairs of Double, adding them as CGPoints to the points arraywhilescanner.scanDouble(&x)&&scanner.scanDouble(&y){points.append(CGPoint(x:x,y:y))}// new point for bezier pathswitchinstruction??""{case"M":path.moveToPoint(points[0])case"C":path.addCurveToPoint(points[2],controlPoint1:points[0],controlPoint2:points[1])case"c":path.addCurveToPoint(path.currentPoint.offset(points[2]),controlPoint1:path.currentPoint.offset(points[0]),controlPoint2:path.currentPoint.offset(points[1]))default:break}}returnpath}
doublex,y;NSMutableArray*points=[NSMutableArrayarray];// scan for pairs of Double, adding them as CGPoints to the points arraywhile([scannerscanDouble:&x]&&[scannerscanDouble:&y]){[pointsaddObject:[NSValuevalueWithCGPoint:CGPointMake(x,y)]];}// new point in pathif([instructionisEqualToString:@"M"]){[pathmoveToPoint:[points[0]CGPointValue]];}elseif([instructionisEqualToString:@"C"]){[pathaddCurveToPoint:[points[2]CGPointValue]controlPoint1:[points[0]CGPointValue]controlPoint2:[points[1]CGPointValue]];}elseif([instructionisEqualToString:@"c"]){CGPointnewPoint=offsetPoint(path.currentPoint,[points[2]CGPointValue]);CGPointcontrol1=offsetPoint(path.currentPoint,[points[0]CGPointValue]);CGPointcontrol2=offsetPoint(path.currentPoint,[points[1]CGPointValue]);[pathaddCurveToPoint:newPointcontrolPoint1:control1controlPoint2:control2];}}[pathapplyTransform:CGAffineTransformMakeScale(1,-1)];returnpath;}

Lo and behold, the result:

NSMustacheScanner

The required flipping, resizing, waxing, and twirling are left as an exercise for the reader.


Swift-Friendly Scanning

As a last note, working with NSScanner in Swift can feel almost silly. Really, NSScanner, I need to pass in a pointer just so you can return a Bool? I can’t use optionals, which are pretty much designed for this exact purpose? Really?

With a simple extension converting the built-in methods to ones returning optional values, scanning becomes far more in sync with Swift’s idiom. Our path data scanning example can now use optional binding instead of inout variables for a cleaner, easier-to-read implementation:

// look for an instruction codewhileletinstruction=scanner.scanCharactersFromSet(instructionSet){varpoints:[CGPoint]=[]// scan for pairs of Double, adding them as CGPoints to the points arraywhileletx=scanner.scanDouble(),y=scanner.scanDouble(){points.append(CGPoint(x:x,y:y))}// new point for bezier pathswitchinstruction{// ...}}

You’ve gotta have the right tools for every job. NSScanner can be the shiny tool to reach for when it’s time to parse a user’s input or a web service’s data. Being able to distinguish which tools are right for which tasks helps us on our way to creating clear and accurate code.

NSCalendar Additions

$
0
0

Dates. More than any other data type, the gulf between the initial banality of dates and their true, multifaceted complexity looms terrifyingly large. Combining sub-second precision, overlapping units, geopolitical time zone boundaries, localization differences in both language and grammar, and Daylight Saving shifts and leap year adjustments that literally add and remove whole chunks of time from measured existence, there’s a lot to process.

To embark on any date-heavy task, then, requires a solid understanding of the tools already at your fingertips. Better to use a Foundation method than to write the n-thousandth version of dateIsTomorrow. Are you using NSDateComponents? Did you specify all the right calendar units? Will your code still work correctly on February 28, 2100?

But here’s the thing: the APIs you’re already using have been holding out on you. Unless you’re digging through release notes and API diffs, you wouldn’t know that over the last few releases of OS X, NSCalendar has quietly built a powerful set of methods for accessing and manipulating dates, and that the latest release brought them all to iOS.

letcalendar=NSCalendar.currentCalendar()
NSCalendar*calendar=[NSCalendarcurrentCalendar];

From new ways of accessing individual date components and flexibly comparing dates to powerful date interpolation and enumeration methods, there’s far too much to ignore. Make some room in your calendar and read on for more.

Convenient Component Access

Oh, NSDateComponents. So practical and flexible, yet so cumbersome when I just. Want to know. What the hour is. NSCalendar to the rescue!

lethour=calendar.component(.CalendarUnitHour,fromDate:NSDate())
NSIntegerhour=[calendarcomponent:NSCalendarUnitHourfromDate:[NSDatedate]];

That’s much better. NSCalendar, what else can you do?

  • getEra(_:year:month:day:fromDate:): Returns the era, year, month, and day of the given date by reference. Pass nil/NULL for any parameters you don’t need.
  • getEra(_:yearForWeekOfYear:weekOfYear:weekday:fromDate:): Returns the era, year (for week of year), week of year, and weekday of the given date by reference. Pass nil/NULL for any parameters you don’t need.
  • getHour(_:minute:second:nanosecond:fromDate:): Returns time information for the given date by reference. nil/NULL, you get the idea.

And just kidding, NSDateComponents, I take it all back. There are a couple methods for you, too:

  • componentsInTimeZone(_:fromDate:): Returns an NSDateComponents instance with components of the given date shifted to the given time zone.
  • components(_:fromDateComponents:toDateComponents:options:): Returns the difference between two NSDateComponents instances. The method will use base values for any components that are not set, so provide at the least the year for each parameter. The options parameter is unused; pass nil/0.

Date Comparison

While direct NSDate comparison has always been a simple matter, more meaningful comparisons can get surprisingly complex. Do two NSDate instances fall on the same day? In the same hour? In the same week?

Fret no more, NSCalendar has you covered with an extensive set of comparison methods:

  • isDateInToday(_:): Returns true if the given date is today.
  • isDateInTomorrow(_:): Returns true if the given date is tomorrow.
  • isDateInYesterday(_:): Returns true if the given date is a part of yesterday.
  • isDateInWeekend(_:): Returns true if the given date is part of a weekend, as defined by the calendar.
  • isDate(_:inSameDayAsDate:): Returns true if the two NSDate instances are on the same day—delving into date components is unnecessary.
  • isDate(_:equalToDate:toUnitGranularity:): Returns true if the dates are identical down to the given unit of granularity. That is, two date instances in the same week would return true if used with calendar.isDate(tuesday, equalToDate: thursday, toUnitGranularity: .CalendarUnitWeekOfYear), even if they fall in different months.
  • compareDate(_:toDate:toUnitGranularity:): Returns an NSComparisonResult, treating as equal any dates that are identical down to the given unit of granularity.
  • date(_:matchesComponents:): Returns true if a date matches the specific components given.

Date Interpolation

Next up is a set of methods that allows you to find the next date(s) based on a starting point. You can find the next (or previous) date based on an NSDateComponents instance, an individual date component, or a specific hour, minute, and second. Each of these methods takes an NSCalendarOptions bitmask parameter that provides fine-grained control over how the next date is selected, particularly in cases where an exact match isn’t found at first.

NSCalendarOptions

The easiest option of NSCalendarOptions is .SearchBackwards, which reverses the direction of each search, for all methods. Backward searches are constructed to return dates similar to forward searches. For example, searching backwards for the previous date with an hour of 11 would give you 11:00, not 11:59, even though 11:59 would technically come “before” 11:00 in a backwards search. Indeed, backward searching is intuitive until you think about it and then unintuitive until you think about it a lot more. That .SearchBackwards is the easy part should give you some idea of what’s ahead.

The remainder of the options in NSCalendarOptions help deal with “missing” time instances. Time can be missing most obviously if one searches in the short window when time leaps an hour forward during a Daylight Saving adjustment, but this behavior can also come into play when searching for dates that don’t quite add up, such as the 31st of February or April.

When encountering missing time, if NSCalendarOptions.MatchStrictly is provided, the methods will continue searching to find an exact match for all components given, even if that means skipping past higher order components. Without strict matching invoked, one of .MatchNextTime, .MatchNextTimePreservingSmallerUnits, and .MatchPreviousTimePreservingSmallerUnits must be provided. These options determine how a missing instance of time will be adjusted to compensate for the components in your request.

In this case, an example will be worth a thousand words:

// begin with Valentine's Day, 2015 at 9:00amletvalentines=cal.dateWithEra(1,year:2015,month:2,day:14,hour:9,minute:0,second:0,nanosecond:0)!// to find the last day of the month, we'll set up a date components instance with // `day` set to 31:letcomponents=NSDateComponents()components.day=31
NSDate*valentines=[calendardateWithEra:1year:2015month:2day:14hour:9minute:0second:0nanosecond:0];NSDateComponents*components=[[NSDateComponentsalloc]init];components.day=31;

Using strict matching will find the next day that matches 31, skipping into March to do so:

calendar.nextDateAfterDate(valentines,matchingComponents:components,options:.MatchStrictly)// Mar 31, 2015, 12:00 AM
NSDate*date=[calendarnextDateAfterDate:valentinesmatchingComponents:componentsoptions:NSCalendarMatchStrictly];// Mar 31, 2015, 12:00 AM

Without strict matching, nextDateAfterDate will stop when it hits the end of February before finding a match—recall that the highest unit specified was the day, so the search will only continue within the next highest unit, the month. At that point, the option you’ve provided will determine the returned date. For example, using .MatchNextTime will pick the next possible day:

calendar.nextDateAfterDate(valentines,matchingComponents:components,options:.MatchNextTime)// Mar 1, 2015, 12:00 AM
date=[calendarnextDateAfterDate:valentinesmatchingComponents:componentsoptions:NSCalendarMatchNextTime];// Mar 1, 2015, 12:00 AM

Similarly, using .MatchNextTimePreservingSmallerUnits will pick the next day, but will also preserve all the units smaller than the given NSCalendarUnitDay:

calendar.nextDateAfterDate(valentines,matchingComponents:components,options:.MatchNextTimePreservingSmallerUnits)// Mar 1, 2015, 9:00 AM
date=[calendarnextDateAfterDate:valentinesmatchingComponents:componentsoptions:NSCalendarMatchNextTimePreservingSmallerUnits];// Mar 1, 2015, 9:00 AM

And finally, using .MatchPreviousTimePreservingSmallerUnits will resolve the missing date by going the other direction, choosing the first possible previous day, again preserving the smaller units:

calendar.nextDateAfterDate(valentines,matchingComponents:components,options:.MatchPreviousTimePreservingSmallerUnits)// Feb 28, 2015, 9:00 AM
date=[calendarnextDateAfterDate:valentinesmatchingComponents:componentsoptions:NSCalendarMatchPreviousTimePreservingSmallerUnits];// Feb 28, 2015, 9:00 AM

Besides the NDateComponents version shown here, it’s worth noting that nextDateAfterDate has two other variations:

// matching a particular calendar unitcal.nextDateAfterDate(valentines,matchingUnit:.CalendarUnitDay,value:31,options:.MatchStrictly)// March 31, 2015, 12:00 AM// matching an hour, minute, and secondcal.nextDateAfterDate(valentines,matchingHour:15,minute:30,second:0,options:.MatchNextTime)// Feb 14, 2015, 3:30 PM
// matching a particular calendar unitdate=[calendarnextDateAfterDate:valentinesmatchingUnit:NSCalendarUnitDayvalue:31options:NSCalendarMatchStrictly];// March 31, 2015, 12:00 AM// matching an hour, minute, and seconddate=[calendarnextDateAfterDate:valentinesmatchingHour:15minute:30second:0options:NSCalendarMatchNextTime];// Feb 14, 2015, 3:30 PM

Enumerating Interpolated Dates

Rather than using nextDateAfterDate iteratively, NSCalendar provides an API for enumerating dates with the same semantics. enumerateDatesStartingAfterDate(_:matchingComponents:options:usingBlock:) computes the dates that match the given set of components and options, calling the provided closure with each date in turn. The closure can set the stop parameter to true, thereby stopping the enumeration.

Putting this new NSCalendarOptions knowledge to use, here’s one way to list the last fifty leap days:

letleapYearComponents=NSDateComponents()leapYearComponents.month=2leapYearComponents.day=29vardateCount=0cal.enumerateDatesStartingAfterDate(NSDate(),matchingComponents:leapYearComponents,options:.MatchStrictly|.SearchBackwards){(date:NSDate!,exactMatch:Bool,stop:UnsafeMutablePointer<ObjCBool>)inprintln(date)if++dateCount==50{// .memory gets at the value of an UnsafeMutablePointerstop.memory=true}}// 2012-02-29 05:00:00 +0000// 2008-02-29 05:00:00 +0000// 2004-02-29 05:00:00 +0000// 2000-02-29 05:00:00 +0000// ...
NSDateComponents*leapYearComponents=[[NSDateComponentsalloc]init];leapYearComponents.month=2;leapYearComponents.day=29;__blockintdateCount=0;[calendarenumerateDatesStartingAfterDate:[NSDatedate]matchingComponents:leapYearComponentsoptions:NSCalendarMatchStrictly|NSCalendarSearchBackwardsusingBlock:^(NSDate*date,BOOLexactMatch,BOOL*stop){NSLog(@"%@",date);if(++dateCount==50){*stop=YES;}}];// 2012-02-29 05:00:00 +0000// 2008-02-29 05:00:00 +0000// 2004-02-29 05:00:00 +0000// 2000-02-29 05:00:00 +0000// ...

Working for the Weekend

If you’re always looking forward to the weekend, look no further than our final two NSCalendar methods:

  • nextWeekendStartDate(_:interval:options:afterDate): Returns the starting date and length of the next weekend by reference via the first two parameters. This method will return false if the current calendar or locale doesn’t support weekends. The only relevant option here is .SearchBackwards. (See below for an example.)
  • rangeOfWeekendStartDate(_:interval:containingDate): Returns the starting date and length of the weekend containing the given date by reference via the first two parameters. This method returns false if the given date is not in fact on a weekend or if the current calendar or locale doesn’t support weekends.

Localized Calendar Symbols

As if all that new functionality wasn’t enough, NSCalendar also provides access to a full set of properly localized calendar symbols, making possible quick access to the names of months, days of the week, and more. Each group of symbols is further enumerated along two axes: (1) the length of the symbol and (2) its use as a standalone noun or as part of a date.

Understanding this second attribute is extremely important for localization, since some languages, Slavic languages in particular, use different noun cases for different contexts. For example, a calendar would need to use one of the standaloneMonthSymbols variants for its headers, not the monthSymbols that are used for formatting specific dates.

For your perusal, here’s a table of all the symbols that are available in NSCalendar—note the different values for standalone symbols in the Russian column:

 en_USru_RU
monthSymbolsJanuary, February, March…января, февраля, марта…
shortMonthSymbolsJan, Feb, Mar…янв., февр., марта…
veryShortMonthSymbolsJ, F, M, A…Я, Ф, М, А…
standaloneMonthSymbolsJanuary, February, March…Январь, Февраль, Март…
shortStandaloneMonthSymbolsJan, Feb, Mar…Янв., Февр., Март…
veryShortStandaloneMonthSymbolsJ, F, M, A…Я, Ф, М, А…
weekdaySymbolsSunday, Monday, Tuesday, Wednesday…воскресенье, понедельник, вторник, среда…
shortWeekdaySymbolsSun, Mon, Tue, Wed…вс, пн, вт, ср…
veryShortWeekdaySymbolsS, M, T, W…вс, пн, вт, ср…
standaloneWeekdaySymbolsSunday, Monday, Tuesday, Wednesday…Воскресенье, Понедельник, Вторник, Среда…
shortStandaloneWeekdaySymbolsSun, Mon, Tue, Wed…Вс, Пн, Вт, Ср…
veryShortStandaloneWeekdaySymbolsS, M, T, W…В, П, В, С…
AMSymbolAMAM
PMSymbolPMPM
quarterSymbols1st quarter, 2nd quarter, 3rd quarter, 4th quarter1-й квартал, 2-й квартал, 3-й квартал, 4-й квартал
shortQuarterSymbolsQ1, Q2, Q3, Q41-й кв., 2-й кв., 3-й кв., 4-й кв.
standaloneQuarterSymbols1st quarter, 2nd quarter, 3rd quarter, 4th quarter1-й квартал, 2-й квартал, 3-й квартал, 4-й квартал
shortStandaloneQuarterSymbolsQ1, Q2, Q3, Q41-й кв., 2-й кв., 3-й кв., 4-й кв.
eraSymbolsBC, ADдо н. э., н. э.
longEraSymbolsBefore Christ, Anno Dominiдо н.э., н.э.

Note: These same collections are also available via NSDateFormatter.

Your Weekly Swiftification

It’s becoming something of a feature here at NSHipster to close with a slightly Swift-ified version of the discussed API. Even in this brand-new set of NSCalendar APIs, there are some sharp edges to be rounded off, replacing UnsafeMutablePointer parameters with more idiomatic tuple return values.

With a useful set of NSCalendar extensions (gist here), the component accessing and weekend finding methods can be used without in-out variables. For example, getting individual date components from a date is much simpler:

// built-invarhour=0varminute=0calendar.getHour(&hour,minute:&minute,second:nil,nanosecond:nil,fromDate:NSDate())// swiftifiedlet(hour,minute,_,_)=calendar.getTimeFromDate(NSDate())

As is fetching the range of the next weekend:

// built-invarstartDate:NSDate?varinterval:NSTimeInterval=0letsuccess=cal.nextWeekendStartDate(&startDate,interval:&interval,options:nil,afterDate:NSDate())ifsuccess,letstartDate=startDate{println("start: \(startDate), interval: \(interval)")}// swiftifiedifletnextWeekend=cal.nextWeekendAfterDate(NSDate()){println("start: \(nextWeekend.startDate), interval: \(nextWeekend.interval)")}

So take that, complicated calendrical math. With these new additions to NSCalendar, you’ll have your problems sorted out in no time.

Quick Look Debugging

$
0
0

Debugging can be an exercise in irony. We create programs that tell our pint-sized supercomputers to complete infinitely varied and incalculable tasks on our behalf, yet when trying to understand those same programs, we tell the computers to wait for us.

For example, suppose I’m trying to figure out why the UINavigationBar in my app doesn’t appear as I expected. To investigate, I might use the debugger to look at the UIColor instance I’m setting on the navigation bar—what color is this, exactly?

UIColor in Debug

Hold on! No more trying to figure out how those components add together. There’s a better way.

Since version 5, Xcode has shipped with Quick Look display in the debugger. Just as you can inspect the contents of a file on the Desktop with a quick tap of the space bar, in Xcode you can use Quick Look to see a visual representation of a variety of datatypes. Tapping the space bar on our color variable gives an instant answer—no off-the-top-of-your-head RGB calculations required:

UIColor Quick Look


You can also invoke Quick Look while debugging directly from your code. Consider the following method, buildPathWithRadius(_:steps:loopCount:). It creates a UIBezierPath of some kind, but you’ve forgotten which, and does this code even work?

funcbuildPathWithRadius(radius:CGFloat,steps:CGFloat,loopCount:CGFloat)->UIBezierPath{letaway=radius/stepsletaround=loopCount/steps*2*CGFloat(M_PI)letpoints=map(stride(from:1,through:steps,by:1)){step->CGPointinletx=cos(step*around)*step*awaylety=sin(step*around)*step*awayreturnCGPoint(x:x,y:y)}letpath=UIBezierPath()path.moveToPoint(CGPoint.zeroPoint)forpointinpoints{path.addLineToPoint(point)}returnpath}
-(UIBezierPath*)buildPathWithRadius:(CGFloat)radiussteps:(CGFloat)stepsloopCount:(CGFloat)loopCount{CGFloatx,y;CGFloataway=radius/steps;CGFloataround=loopCount/steps*2*M_PI;UIBezierPath*path=[UIBezierPathbezierPath];[pathmoveToPoint:CGPointZero];for(inti=1;i<=steps;i++){x=cos(i*around)*i*away;y=sin(i*around)*i*away;[pathaddLineToPoint:CGPointMake(x,y)];}returnpath;}

To see the result, you could surely create a custom view for the bezier path or draw it into a UIImage. But better yet, you could insert a breakpoint at the end of the method and mouse over path:

Spiral UIBezierPath Quick Look

Spiraltastic!


Built-In Types

Quick Look can be used with most of the datatypes you’ll want to visualize right out of the box. Xcode already has you covered for the following types:

  • Images:UIImage, NSImage, UIImageView, NSImageView, CIImage, and NSBitmapImageRep are all visible via Quick Look.
  • Colors:UIColor and NSColor. (Sorry, CGColor.)
  • Strings:NSString and NSAttributedString.
  • Geometry:UIBezierPath and NSBezierPath along with CGPoint, CGRect, and CGSize.
  • Locations:CLLocation gives a large, interactive view of the mapped location, with details about altitude and accuracy in an overlay.
  • URLs:NSURL is represented by a view showing the local or remote content addressed by the URL.
  • Cursors:NSCursor, for the cursored among us.
  • SpriteKit:SKSpriteNode, SKShapeNode, SKTexture, and SKTextureAtlas are all represented.
  • Data:NSData has a great view showing hex and ASCII values with their offset.
  • Views: Last but not least, any UIView subclass will display its contents in a Quick Look popup—so convenient.

What’s more, these Quick Look popups often include a button that will open the content in a related application. Image data (as well as views, cursors, and SpriteKit types) offer an option to open in Preview. Remote URLs can be opened in Safari; local ones can be opened in the related application. Finally, plain-text and attributed string data can likewise be opened in TextEdit.

Custom Types

For anything beyond these built-in types, Xcode 6 has added Quick Look for custom objects. The implementation couldn’t be simpler—add a single debugQuickLookObject() method to any NSObject-derived class, and you’re set. debugQuickLookObject() can then return any of the built-in types described above, configured for your custom type’s needs:

funcdebugQuickLookObject()->AnyObject{letpath=buildPathWithRadius(radius,steps:steps,loopCount:loopCount)returnpath}
-(id)debugQuickLookObject{UIBezierPath*path=[selfbuildPathWithRadius:self.radiussteps:self.stepsloopCount:self.loopCount];returnpath;}

In sum, Quick Look enables a more direct relationship with the data we manipulate in our code by allowing us to iterate over smaller pieces of functionality. This direct view into previously obfuscated datatypes brings some of the immediacy of a Swift Playground right into our main codebase. Displaying images? Visualizing data? Rendering text? Computers are so good at all that! Let’s let them do it from now on.

Unmanaged

$
0
0

APIs do more than just exposing functionality to developers. They also communicate values about how the API should be used and why. This communication is what makes naming things one of the Hard Parts of computer science; it’s what separates the good APIs from the great.

A reading of Swift’s standard library shows a clear demarcation between the safety and reliability that Swift advertises on one side and the tools necessary for Objective-C interoperability on the other. Types with names like Int, String, and Array let you expect straightforward usage and unsurprising behavior, while it’s impossible to create an UnsafeMutablePointer or Unmanaged instance without thinking “here be dragons.”

Here we take a look at Unmanaged, a wrapper for unclearly-memory-managed objects and the hot-potatoesque way of properly handling them. But to start, let’s rewind the clock a bit.

Automatic Reference Counting

Back in the Stone Age (aka 2011), reference counting in Objective-C was still a manual affair. Each reference-retaining operation needed to be balanced with a corresponding release, lest an application’s memory take on an air of phantasmagoria, with zombies dangling and memory leaking… Gross. Carefully tending the reference count of one’s objects was a constant chore for developers and a major hurdle for newcomers to the platform.

The advent of automatic reference counting (ARC) made all of that manual memory management unnecessary. Under ARC, the compiler inserts the retain/release/autorelease calls for you, reducing the cognitive load of applying the rules at every turn. If this graphic doesn’t convince you of the boon of dropping manual memory management, nothing will:

Memory management before and after ARC

Now, in this post-ARC world, all Objective-C and Core Foundation types returned from Objective-C methods are automatically memory managed, leaving Core Foundation types returned from C functions as the lone holdout. For this last category, management of an object’s ownership is still done with calls to CFRetain() and CFRelease() or by bridging to Objective-C objects with one of the __bridge functions.

To help understand whether or not a C function returns objects that are owned by the caller, Apple uses naming conventions defined by the Create Rule and the Get Rule:

  • The Create Rule states that a function with Create or Copy in its name returns ownerships to the call of the function. That is to say, the caller of a Create or Copy function will eventually need to call CFRelease on the returned object.

  • The Get Rule isn’t so much a rule of its own as it is a catch-all for everything that doesn’t follow the Create Rule. A function doesn’t have Create or Copy in its name? It follows the Get rule instead, returning without transferring ownership. If you want the returned object to persist, in most cases it’s up to you to retain it.

If you’re a belt-and-suspenders-and-elastic-waistband programmer like I am, check the documentation as well. Even when they follow the proper name convention, most APIs also explicitly state which rule they follow, and any exceptions to the common cases.

Wait—this article is about Swift. Let’s get back on track.

Swift uses ARC exclusively, so there’s no room for a call to CFRelease or __bridge_retained. How does Swift reconcile this “management-by-convention” philosophy with its guarantees of memory safety?

This occurs in two different ways. For annotated APIs, Swift is able to make the conventions explicit—annotated CoreFoundation APIs are completely memory-managed and provide the same promise of memory safety as do bridged Objective-C or native Swift types. For unannotated APIs, however, Swift passes the job to you, the programmer, through the Unmanaged type.

Managing Unmanaged

While most CoreFoundation APIs have been annotated, some significant chunks have yet to receive attention. As of this writing, the Address Book framework seems the highest profile of the unannotated APIs, with several functions taking or returning Unmanaged-wrapped types.

An Unmanaged<T> instance wraps a CoreFoundation type T, preserving a reference to the underlying object as long as the Unmanaged instance itself is in scope. There are two ways to get a Swift-managed value out of an Unmanaged instance:

  • takeRetainedValue(): returns a Swift-managed reference to the wrapped instance, decrementing the reference count while doing so—use with the return value of a Create Rule function.

  • takeUnretainedValue(): returns a Swift-managed reference to the wrapped instance without decrementing the reference count—use with the return value of a Get Rule function.

In practice, you’re better off not even working with Unmanaged instances directly. Instead, take... the underlying instance immediately from the function’s return value and bind that.

Let’s take a look at this in practice. Suppose we wish to create an ABAddressBook and fetch the name of the user’s best friend:

letbestFriendID=ABRecordID(...)// Create Rule - retainedletaddressBook:ABAddressBook=ABAddressBookCreateWithOptions(nil,nil).takeRetainedValue()iflet// Get Rule - unretainedbestFriendRecord:ABRecord=ABAddressBookGetPersonWithRecordID(addressBook,bestFriendID)?.takeUnretainedValue(),// Create Rule (Copy) - retainedname=ABRecordCopyCompositeName(bestFriendRecord)?.takeRetainedValue()as?String{println("\(name): BFF!")// Rhonda Shorsheimer: BFF!}

With Swift 1.2’s improved optional bindings, it’s a piece of cake to unwrap, take the underlying value, and cast to a Swift type.

Better Off Without

Now that we’ve looked at how to work with Unmanaged, let’s look at how to get rid of it altogether. If Unmanaged references are returned from calls to your own C functions, you’re better off using annotations. Annotations let the compiler know how to automatically memory-manage your return value: instead of an Unmanaged<CFString>, you receive a CFString, which is type-safe and fully memory-managed by Swift.

For example, let’s take a function that combines two CFString instances and annotate that function to tell Swift how to memory-manage the resulting string. Following the naming conventions described above, our function will be called CreateJoinedString—that name communicates that the caller will own the returned string.

CFStringRefCreateJoinedString(CFStringRefstring1,CFStringRefstring2);

Sure enough, in the implementation you can see that this creates resultString with CFStringCreateMutableCopy and returns it without a balancing CFRelease:

CFStringRefCreateJoinedString(CFStringRefstring1,CFStringRefstring2){CFMutableStringRefresultString=CFStringCreateMutableCopy(NULL,0,string1);CFStringAppend(resultString,string2);returnresultString;}

In our Swift code, just as above, we still need to manage the memory manually. Our function is imported as returning an Unmanaged<CFString>!:

// imported declaration:funcCreateJoinedString(string1:CFString!,string2:CFString!)->Unmanaged<CFString>!// to call:letjoinedString=CreateJoinedString("First","Second").takeRetainedValue()asString

Since our function follows the naming conventions described in the Create Rule, we can turn on the compiler’s implicit bridging to eliminate the Unmanaged wrapper. Core Foundation provides two macros—namely, CF_IMPLICIT_BRIDGING_ENABLED and CF_IMPLICIT_BRIDGING_DISABLED—that turn on and off the Clang arc_cf_code_audited attribute:

CF_IMPLICIT_BRIDGING_ENABLED// get rid of Unmanaged#pragma clang assume_nonnull begin      // also get rid of !sCFStringRefCreateJoinedString(CFStringRefstring1,CFStringRefstring2);#pragma clang assume_nonnull endCF_IMPLICIT_BRIDGING_DISABLED

Because Swift now handles the memory management for this return value, our code is simpler and skips use of Unmanaged altogether:

// imported declaration:funcCreateJoinedString(string1:CFString,string2:CFString)->CFString// to call:letjoinedString=CreateJoinedString("First","Second")asString

Finally, when your function naming doesn’t comply with the Create/Get Rules, there’s an obvious fix: rename your function to comply with the Create/Get Rules. Of course, in practice, that’s not always an easy fix, but having an API that communicates clearly and consistently pays dividends beyond just avoiding Unmanaged. If renaming isn’t an option, there are two other annotations to use: functions that pass ownership to the caller should use CF_RETURNS_RETAINED, while those that don’t should use CF_RETURNS_NOT_RETAINED. For instance, the poorly-named MakeJoinedString is shown here with manual annotations:

CF_RETURNS_RETAINED__nonnullCFStringRefMakeJoinedString(__nonnullCFStringRefstring1,__nonnullCFStringRefstring2);

One gets that feeling that Unmanaged is a stopgap measure—that is, a way to use CoreFoundation while the work of annotating the mammoth API is still in progress. As functions are revised to interoperate more cleanly, each successive Xcode release may allow you to strip takeRetainedValue() calls from your codebase. Yet until the sun sets on the last CFUnannotatedFunctionRef, Unmanaged will be there to help you bridge the gap.

Swift Documentation

$
0
0

Code structure and organization is a matter of pride for developers. Clear and consistent code signifies clear and consistent thought. Even though the compiler lacks a discerning palate when it comes to naming, whitespace, or documentation, it makes all of the difference for human collaborators.

Readers of NSHipster will no doubt remember the article about documentation published last year, but a lot has changed with Xcode 6 (fortunately, for the better, in most cases). So this week, we’ll be documenting the here and now of documentation for aspiring Swift developers.

Let’s dive in.


Since the early 00’s, Headerdoc has been the documentation standard preferred by Apple. Starting off as little more than a Perl script parsing trumped-up Javadoc comments, Headerdoc would eventually be the engine behind Apple’s developer documentation online and in Xcode.

With the announcements of WWDC 2014, the developer documentation was overhauled with a sleek new design that could accommodate switching between Swift & Objective-C. (If you’ve checked out any of the new iOS 8 APIs online, you’ve seen this in action)

What really comes as a surprise is that the format of documentation appears to have changed as well.

In the midst of Swift code, Headerdoc comments are not parsed correctly when invoking Quick Documentation (⌥ʘ):

/**    Lorem ipsum dolor sit amet.    @param bar Consectetur adipisicing elit.    @return Sed do eiusmod tempor.*/funcfoo(bar:String)->AnyObject{...}

Unrecognized Headerdoc

What is parsed, however, is something markedly different:

New Recognized Format

/**    Lorem ipsum dolor sit amet.    - parameter bar: Consectetur adipisicing elit.    - returns: Sed do eiusmod tempor.*/funcfoo(bar:String)->AnyObject{...}

So what is this not-so-strange new documentation format? After a yearlong sojourn in the lands of reStructuredText, Xcode 7 has settled on a Swift-flavored version of Markdown.

Basic Markup

Documentation comments are distinguished by using /** ... */ for multi-line comments or /// for single-line comments. Inside comment blocks, the conventions you’ve gotten used to when writing Markdown everywhere else apply:

  • Paragraphs are separated by blank lines
  • Unordered lists can use a variety of bullet characters: -, +, *,
  • Ordered lists use Arabic numerals (1, 2, 3, …) followed by a period 1. or right parenthesis 1):
  • Headers can be marked with preceding # signs or by underlining with = or -.
  • Even links and images work, with web-based images pulled down and displayed directly in Xcode.
/**    # Lists    You can apply *italic*, **bold**, or `code` inline styles.    ## Unordered Lists    - Lists are great,    - but perhaps don't nest    - Sub-list formatting      - isn't the best.    ## Ordered Lists    1. Ordered lists, too    2. for things that are sorted;    3. Arabic numerals    4. are the only kind supported.*/

Parameters & Return Values

Xcode 7 recognizes and makes separate from a symbol’s description a few special fields. The parameters, return value, and a new “throws” section (to go with Swift 2.0’s new throws keyword) are broken out in the Quick Help popover and inspector when styled as a bulleted item followed by a colon (:).

  • Parameters: Start the line with Parameter <param name>: and the description of the parameter.
  • Return values: Start the line with Returns: and information about the return value.
  • Thrown errors: Start the line with Throws: and a description of the errors that can be thrown. Since Swift doesn’t type-check thrown errors beyond ErrorType conformance, it’s especially important to document errors properly.
/**    Repeats a string `times` times.    - Parameter str:   The string to repeat.    - Parameter times: The number of times to repeat `str`.    - Throws: `MyError.InvalidTimes` if the `times` parameter         is less than zero.    - Returns: A new string with `str` repeated `times` times.*/funcrepeatString(str:String,times:Int)throws->String{guardtimes>=0else{throwMyError.InvalidTimes}returnRepeat(count:5,repeatedValue:"Hello").joinWithSeparator("")}

A longer list of parameters can be broken out into a sublist by using the Parameters: prefix. Simply indent each parameter in a bulleted list below.

/// Returns the magnitude of a vector in three dimensions/// from the given components.////// - Parameters:///     - x: The *x* component of the vector.///     - y: The *y* component of the vector.///     - z: The *z* component of the vector.funcmagnitude3D(x:Double,y:Double,z:Double)->Double{returnsqrt(pow(x,2)+pow(y,2)+pow(z,2))}

Description Fields

Swift-flavored Markdown includes another set of field headers to break out particular sections of a type or method’s description, formatted just as Returns and Throws above. Loosely organized, the recognized headers are:

  • Algorithm/Safety Information:Precondition, Postcondition, Requires, Invariant, Complexity, Important, Warning
  • Metadata: Author, Authors, Copyright, Date, SeeAlso, Since, Version
  • General Notes & Exhortations:Attention, Bug, Experiment, Note, Remark, ToDo

No matter which you choose, all fields are rendered as a bold header followed by a block of text:

Field Header:
The text of the subfield is displayed starting on the next line.

Code blocks

Code blocks can be embedded in documentation comments as well, which can be useful for demonstrating proper usage or implementation details. Inset the code block by at least four spaces:

/**    The area of the `Shape` instance.    Computation depends on the shape of the instance.     For a triangle, `area` will be equivalent to:        let height = triangle.calculateHeight()        let area = triangle.base * height / 2*/vararea:CGFloat{get}

Fenced code blocks are also recognized, with three backticks (&grave;) or tildes (~) marking the beginning and end of a block:

/**    The perimeter of the `Shape` instance.    Computation depends on the shape of the instance, and is    equivalent to:     ```    // Circles:    let perimeter = circle.radius * 2 * CGFloat(M_PI)    // Other shapes:    let perimeter = shape.sides.map { $0.length }                               .reduce(0, combine: +)    ```*/varperimeter:CGFloat{get}

Documentation Is My New Bicycle

How does this look when applied to an entire class? Quite nice, actually:

importFoundation/// 🚲 A two-wheeled, human-powered mode of transportation.classBicycle{/**        Frame and construction style.        - Road: For streets or trails.        - Touring: For long journeys.        - Cruiser: For casual trips around town.        - Hybrid: For general-purpose transportation.    */enumStyle{caseRoad,Touring,Cruiser,Hybrid}/**        Mechanism for converting pedal power into motion.        - Fixed: A single, fixed gear.        - Freewheel: A variable-speed, disengageable gear.    */enumGearing{caseFixedcaseFreewheel(speeds:Int)}/**        Hardware used for steering.        - Riser: A casual handlebar.        - Café: An upright handlebar.        - Drop: A classic handlebar.        - Bullhorn: A powerful handlebar.    */enumHandlebar{caseRiser,Café,Drop,Bullhorn}/// The style of the bicycle.letstyle:Style/// The gearing of the bicycle.letgearing:Gearing/// The handlebar of the bicycle.lethandlebar:Handlebar/// The size of the frame, in centimeters.letframeSize:Int/// The number of trips travelled by the bicycle.private(set)varnumberOfTrips:Int/// The total distance travelled by the bicycle, in meters.private(set)vardistanceTravelled:Double/**        Initializes a new bicycle with the provided parts and specifications.        - Parameters:            - style: The style of the bicycle            - gearing: The gearing of the bicycle            - handlebar: The handlebar of the bicycle            - frameSize: The frame size of the bicycle, in centimeters        - Returns: A beautiful, brand-new bicycle, custom built          just for you.    */init(style:Style,gearing:Gearing,handlebar:Handlebar,frameSizecentimeters:Int){self.style=styleself.gearing=gearingself.handlebar=handlebarself.frameSize=centimetersself.numberOfTrips=0self.distanceTravelled=0}/**        Take a bike out for a spin.        - Parameter meters: The distance to travel in meters.    */functravel(distancemeters:Double){ifmeters>0{distanceTravelled+=meters++numberOfTrips}}}

Option-click on the Styleenum declaration, and the description renders beautifully with a bulleted list:

Swift enum Declaration Documentation

Open Quick Documentation for the method travel, and the parameter is parsed out into a separate field, as expected:

Swift func Declaration Documentation

MARK / TODO / FIXME

In Objective-C, the pre-processor directive #pragma mark is used to divide functionality into meaningful, easy-to-navigate sections. In Swift, there are no pre-processor directives (closest are the similarly-octothorp’d build configurations), but the same can be accomplished with the comment // MARK:.

As of Xcode 6β4, the following comments will be surfaced in the Xcode source navigator:

  • // MARK:(As with #pragma, marks followed by a single dash (-) will be preceded with a horizontal divider)
  • // TODO:
  • // FIXME:

Other conventional comment tags, such as NOTE and XXX are not recognized by Xcode.

To show these new tags in action, here’s how the Bicycle class could be extended to adopt the Printable protocol, and implement description.

Xcode 6 Documentation Source Navigator MARK / TODO / FIXME

// MARK: CustomStringConvertibleextensionBicycle:CustomStringConvertible{publicvardescription:String{vardescriptors:[String]=[]switchself.style{case.Road:descriptors.append("A road bike for streets or trails")case.Touring:descriptors.append("A touring bike for long journeys")case.Cruiser:descriptors.append("A cruiser bike for casual trips around town")case.Hybrid:descriptors.append("A hybrid bike for general-purpose transportation")}switchself.gearing{case.Fixed:descriptors.append("with a single, fixed gear")case.Freewheel(letn):descriptors.append("with a \(n)-speed freewheel gear")}switchself.handlebar{case.Riser:descriptors.append("and casual, riser handlebars")case.Café:descriptors.append("and upright, café handlebars")case.Drop:descriptors.append("and classic, drop handlebars")case.Bullhorn:descriptors.append("and powerful bullhorn handlebars")}descriptors.append("on a \(frameSize)\" frame")// FIXME: Use a distance formatterdescriptors.append("with a total of \(distanceTravelled) meters traveled over \(numberOfTrips) trips.")// TODO: Allow bikes to be named?returndescriptors.joinWithSeparator(", ")}}

Bringing everything together in code:

letbike=Bicycle(style:.Road,gearing:.Freewheel(speeds:8),handlebar:.Drop,frameSize:53)bike.travel(distance:1_500)// Trip around the townbike.travel(distance:200)// Trip to the storeprint(bike)// "A road bike for streets or trails, with a 8-speed freewheel gear, and classic, drop handlebars, on a 53" frame, with a total of 1700.0 meters traveled over 2 trips."

Jazzy

Jazzy is a terrific open-source command-line utility that transforms your project’s documentation comments into a set of Apple-like HTML documentation. Jazzy uses Xcode’s SourceKitService to read your beautifully written type and method descriptions. Install Jazzy as a gem, then simply run from the root of your project folder.

$ [sudo] gem install jazzy
$ jazzy
Running xcodebuild
Parsing ...
building site
jam out ♪♫ to your fresh new docs in `docs`

Take a peek at a Jazzy-generated docset for the Bicycle class.


Although the tooling and documentation around Swift is still rapidly evolving, one would be wise to adopt good habits early, by using the new Markdown capabilities for documentation, as well as MARK: comments in Swift code going forward.

Go ahead and add it to your TODO: list.


XCPlayground

$
0
0

Stop right there! Given the topic, wouldn’t you rather read this article as a Playground? Download Now →

Play.

Given the association of play with childish exuberance, one could define play as the opposite of work. And yet, the elements of play are what we do in our line of work every day: experimentation, exploration, discovery.

Playgrounds aren’t a feature of the Swift language per se—instead, they are a terrific showcase for all that Swift has to offer, from its efficiency and power to its opacity and depth. Playgrounds make it truly simple to create a working program—indeed, every new Playground starts with the soon-familiar "Hello, playground". At the same time, Playgrounds hide some of their most powerful features, leaving exploration as the only means to discovering their rapidly advancing capabilities.

This week, we’ll take a look past the surface of Playgrounds, giving you tools to make them a powerful part of your development process. Read on for more about Playground sources and resources, captured values and extended execution, and integrated rich formatting that can transform a Playground into an interactive teaching tool.

Note: The digital version of the recently released NSHipster: Obscure Topics in Cocoa & Swift includes a package of Playgrounds—one for every chapter in the book. Each Playground provides a chance to explore and experiment with the concepts presented therein, including extended examples.

Sources

The revamped Playground package structure includes a “Sources” folder for code that is more stable than experimental. All files in the “Sources” directory are compiled (just once, not every time you press a key) into a single module and automatically imported into the Playground. In addition to simplifying the code in your Playground, this compilation drastically speeds up execution. This means that if I have defined a type, function, or global constant in those files with public accessibility, I can use it in a Playground without further ado:

Compiled Sources

To get started in your own Playground, open the Project Navigator (⌘1) and expand the Playground file to see the “Sources” directory.

Importing Frameworks

To import an external framework, create a new Xcode Workspace that contains both the framework project and your Playground. After building the framework, it can be imported with a standard import statement.

Resources

No playground is complete without a sandbox to play in, and Swift Playgrounds don’t disappoint. Playgrounds have two places to keep associated resources: one local to each individual playground and a second shared amongst all of them. Being able to load and work with XML, JSON data, XIBs, and images extends the usefulness of your Playground experimentation.

Local

The Resources folder, embedded in the Playground package alongside Sources, is visible in the Project Navigator—simply drag and drop images or data files to use them in your Playground. The contents are then available via the main bundle. For example, we can easily load a JSON file filled with weather data:

letjsonPath=NSBundle.mainBundle().bundlePath.stringByAppendingPathComponent("weather.json")ifletjsonData=NSData(contentsOfFile:jsonPath),json=NSJSONSerialization.JSONObjectWithData(jsonData,options:nil,error:nil)as?[String:AnyObject]{// ...}

Shared

The contents of a “Shared Playground Data” directory inside your “Documents” folder are available to any Playground you create. Access the shared folder via the XCPSharedDataDirectoryPath constant.

To try this out yourself, you’ll need to create the directory at “~/Documents/Shared Playground Data”. Here we’re attempting to load an image named “image.png”:

letsharedImagePath=XCPSharedDataDirectoryPath.stringByAppendingPathComponent("image.png")ifletimage=UIImage(contentsOfFile:sharedImagePath){// ...}

Captured Values

A Playground normally shows the results of simple expressions immediately. Arrays, strings, numbers, and more have their values shown in the results pane as they are calculated. But what about values that change over time?

By using the XCPCaptureValue() function, we can build a graph of a changing value over a series of iterations. Returning to our weather sample, let’s take a look at the hourly temperatures in the data, using XCPCaptureValue to display the value of temperature in the Assistant Editor’s timeline view:

importXCPlaygroundforforecastinforecasts{iflettempString=forecast["temp"]?["english"]as?String,temperature=tempString.toInt(){XCPCaptureValue("Temperature",temperature)}}

Alternatively, choosing Editor → Show Result For Current Line will capture the current line’s values and display the chart directly in the flow of the Playground:

Result for Current Line

Asynchronous Execution

Unlike most Swift code that is written as part of an app or framework, Playgrounds are treated as top-level code. Top-level code in a Playground is executed instruction-by-instruction in order, from top to bottom. This container-less style of execution provides immediate feedback, but there is one problem: execution halts as soon as it reaches the end of the Playground. Network requests, timers, and long-running background queues are abandoned before they can return to report on success or failure.

To keep execution going long enough to see the results of these kinds of asynchronous operations, the XCPlayground module includes a function that extends the length of the process:

importXCPlaygroundXCPSetExecutionShouldContinueIndefinitely(continueIndefinitely:true)leturl=NSURL(string:"http://httpbin.org/image/png")!lettask=NSURLSession.sharedSession().dataTaskWithURL(url){data,_,_inletimage=UIImage(data:data)// ...}task.resume()

In addition to the code in a Playground, Swift code run from the command line in a scripting file, in the Swift REPL, or in a project’s optional “main.swift” file is also considered top-level code. Along with order-dependent execution, top-level code is the only kind that can contain statements outside of a function or encapsulated within a type.

Documentation

Beyond experimentation, Playgrounds are also powerful for demonstrating tools and frameworks in the Swift language. Special documentation sections can be rendered as rich text, giving clear narration to code that demonstrates a technique or the correct way to use a library.

Unlike Swift’s other documentation syntax, Swift Playgrounds use Markdown for richly formatted text. (If you downloaded the Playground for this post, you’re reading Markdown right now.) A colon (:) added to a single- or multi-line comment marker signifies a rich-text comment:

//: This line will have **bold** and *italic* text./*:## Headers of All Sizes### Lists of Links- [NSHipster](http://nshipster.com)- [ASCIIwwdc](http://asciiwwdc.com)- [SwiftDoc](http://swiftdoc.org)### Images, Too![Remote Image](http://nshipster.s3.amazonaws.com/alert.gif)![Local Image](bomb.gif) *Images in the Resources directory can be referenced locally**/

Rendered Documentation

It’s possible to toggle rich documentation rendering either by selecting the Editor → Show Rendered Markup menu item or by checking the Render Documentation checkbox in the File Inspector (⌘⌥1).


Playgrounds represent a major shift in the way we share and learn about tools for OS X and iOS. A Playground can demonstrate each feature and provide a space for potential users to discover and explore the library you’ve created. Trade out your static README.md for an interactive README.playground and let the play begin anew.

MirrorType

$
0
0

Reflection in Swift is a limited affair, providing read-only access to a subset of type metadata. While far from the rich array of run-time hackery familiar to seasoned Objective-C developers, Swift’s tools enable the immediate feedback and sense of exploration offered by Xcode Playgrounds.

Perhaps Swift’s strict type checking obviates the need for reflection. With variable types typically known at compile time, there might not be cause for further examination or branching. Then again, a hefty number of Cocoa APIs dole out AnyObject instances at the drop of a hat, leaving us to cast about for the matching type.

This week, we’ll reflect on reflection in Swift, its mirror types, and MirrorType, the protocol that binds them together.


MirrorType

The entry point for reflection is the reflect function, which can take an instance of any type as its single parameter and returns a MirrorType. Now, MirrorType is something of an oddity for the Swift standard libary: a protocol used as a type. Other than the ubiquitous AnyObject, to date no other protocol is used this way. The particular MirrorType-conforming instance that you receive depends on the type passed to reflect—Swift’s internals define mirrors for types such as Array, Dictionary, Optional, and Range, along with more generic mirrors for structs, classes, tuples, and metatypes.

MirrorType provides the nascent reflection API that Swift offers, wrapping a value along with its type information, information about its children, and different representations of the instance. Mirrors have the following properties:

  • value: access to the original reflected value, but with type Any.
  • valueType: the Type of the original reflected value—equivalent to value.dynamicType.
  • count: the number of logical children. For a collection, like Array or Set, this is the number of elements; for a struct, this is the number of stored properties.
  • disposition: a value from the MirrorDisposition enumeration, intended to help the IDE choose how to display the value. MirrorDisposition has eleven cases:
    • IndexContainer, KeyContainer, MembershipContainer, Container: used for collections.
    • Optional: used for optional values. Implicitly unwrapped optionals are skipped over by reflect() to fetch the reflection of the unwrapped value.
    • Aggregate: used for Swift types that bridge to Objective-C and for Objective-C types that have been augmented for use with Swift. For example, Float has an Aggregate disposition while the non-bridged Float80 returns Struct, and UIView (extended for Reflectable conformance), has an Aggregate disposition while the unadorned UIBarButtonItem returns ObjCObject.
    • ObjCObject: by contrast with Aggregate, used for unextended Objective-C classes.
    • Tuple: used for tuple values.
    • Struct, Class, Enum: used as fallback cases for types that don’t fall into any of the above categories.
  • objectIdentifier: the unique object identifier for a class or metatype instance.
  • summary: a string description of the value.
  • quickLookObject: a QuickLookObject instance holding a visual or text representation of the value. Its behavior is similar to the debugQuickLookObjectwe covered a few weeks back.

Additionally, a mirror has an Int-based subscript that returns a (String, MirrorType) tuple for each child. That’s the name of the property/key/index and a mirror of the value.

So how can we put MirrorType to use? Let’s suppose we have a group of numbers in a tuple that we want to use for a lottery ticket, but we need to convert them to an [Int] array first:

letlotteryTuple=(4,8,15,16,23,42)

Rather than extracting the pieces of the tuple one by one (i.e., lotteryType.0, lotteryTuple.1, etc.), we can use reflect() to iterate over the elements:

// create a mirror of the tupleletlotteryMirror=reflect(lotteryTuple)// loop over the elements of the mirror to build an arrayvarlotteryArray:[Int]=[]foriin0..<lotteryMirror.count{let(index,mirror)=lotteryMirror[i]ifletnumber=mirror.valueas?Int{lotteryArray.append(number)}}println(lotteryArray)// [4, 8, 15, 16, 23, 42]

Not bad.

Mapping a Mirror

If we could map over the elements in a mirror, reflecting over an instance’s properties or elements would be a bit easier. Let’s write a mapReflection function that takes an instance of any type and a transforming closure:

funcmapReflection<T,U>(x:T,@noescapetransform:(String,MirrorType)->U)->[U]{varresult:[U]=[]letmirror=reflect(x)foriin0..<mirror.count{result.append(transform(mirror[i]))}returnresult}

Now we can quite simply print all the logical children of any instance:

letprintChild:(String,MirrorType)->()={println("\($0): \($1.value)")}mapReflection(lotteryTuple,printChild)// .0: 4// .1: 8// ...mapReflection(lotteryArray,printChild)// [0]: 4// [1]: 8// ...mapReflection(CGRect.zeroRect,printChild)// origin: (0.0, 0.0)// size: (0.0, 0.0)

That output might look familiar to those who have used Swift’s dump function before. dump uses reflection recursively to print out an instance’s children, their children, and so on:

dump(CGRect.zeroRect)// ▿ (0.0, 0.0, 0.0, 0.0)//   ▿ origin: (0.0, 0.0)//     - x: 0.0//     - y: 0.0//   ▿ size: (0.0, 0.0)//     - width: 0.0//     - height: 0.0

Custom-Cut Mirrors

Beyond dump, Xcode also uses mirrors extensively for the display of values in a Playground, both in the results pane on the right side of a Playground window and in captured value displays. Custom types don’t start out with a custom mirror, so their display can leave something to be desired. Let’s look at the default behavior of a custom type in a Playground and then see how a custom MirrorType can improve that display.

For our custom type, we’ll use a simple struct to hold information about a WWDC session:

/// Information for a single WWDC session.structWWDCSession{/// An enumeration of the different WWDC tracks.enumTrack:String{caseFeatured="Featured"caseAppFrameworks="App Frameworks"caseDistribution="Distribution"caseDeveloperTools="Developer Tools"caseMedia="Media"caseGraphicsAndGames="Graphics & Games"caseSystemFrameworks="System Frameworks"caseDesign="Design"}letnumber:Intlettitle:Stringlettrack:Trackletsummary:String?}letsession801=WWDCSession(number:801,title:"Designing for Future Hardware",track:.Design,summary:"Design for tomorrow's products today. See examples...")

By default, reflection on a WWDCSession instance uses the built-in _StructMirror type. This provides a property-based summary on the right (useful) but only the class name in a captured value pane (not so useful):

Default WWDCSession Representation

To provide a richer representation of a WWDCSession, we’ll implement a new type, WWDCSessionMirror. This type must conform to MirrorType, including all the properties listed above:

structWWDCSessionMirror:MirrorType{privatelet_value:WWDCSessioninit(_value:WWDCSession){_value=value}varvalue:Any{return_value}varvalueType:Any.Type{returnWWDCSession.self}varobjectIdentifier:ObjectIdentifier?{returnnil}vardisposition:MirrorDisposition{return.Struct}// MARK: Child propertiesvarcount:Int{return4}subscript(index:Int)->(String,MirrorType){switchindex{case0:return("number",reflect(_value.number))case1:return("title",reflect(_value.title))case2:return("track",reflect(_value.track))case3:return("summary",reflect(_value.summary))default:fatalError("Index out of range")}}// MARK: Custom representationvarsummary:String{return"WWDCSession \(_value.number) [\(_value.track.rawValue)]: \(_value.title)"}varquickLookObject:QuickLookObject?{return.Text(summary)}}

In the summary and quickLookObject properties, we provide our custom representation of a WWDCSession—a nicely formatted string. Note, in particular, that the implementation of count and the subscript are completely manual. The default mirror types ignore private and internal access modifiers, so a custom mirror could be used to hide implementation details, even from reflection.

Lastly, we must link WWDCSession to its custom mirror by adding conformance to the Reflectable protocol. Conformance only requires a single new method, getMirror(), which returns a MirrorType—in this case, our shiny new WWDCSessionMirror:

extensionWWDCSession:Reflectable{funcgetMirror()->MirrorType{returnWWDCSessionMirror(self)}}

That’s it! The Playground now uses our custom representation instead of the default:

Custom WWDCSession Representation

In the absence of Printable conformance, println() and toString() will also pull the string representation from an instance’s mirror.


In its current form, Swift reflection is more novelty than powerful feature. With new Swift functionality surely right around the corner at WWDC, this article may prove to have a very short shelf life indeed. But in the mean time, should you find the need for introspection, you’ll know just where to look.

NSHipster Quiz #7

$
0
0

On June 9th, we organized the third annual WWDC edition of the NSHipster Pub Quiz, with topics ranging from pop cultural trivia to technical pedantry. A huge thanks to Realm, who opened their offices and hosted with aplomb the scores of developers who turned out for the quiz.

With dozens of teams competing for the prizes on offer, competition was fierce. After the final tally, Team “U+1F4A9” (aka “💩 PILE OF POO”) took the top prize with a score of 35 points. Congratulations to Benjamin Encz, Dave Verwer, Emilio Peláez, Jeffrey Bergier, Michael Helmbrecht, and Warren Moore on the win!

As always, you can play along at home or at work with your colleagues. Here are the rules:

  • Four rounds of ten questions each
  • Record your answers on a separate sheet of paper
  • Each correct answer to a question gets you 1 point (unless otherwise specified)
  • Play with up to five friends for maximum enjoyment
  • Don’t be lame and look things up on the Internet or in Xcode

Round 1: General Knowledge

  1. What 1989 movie introduces its protagonist free climbing El Capitan, to disastrous effect?
  2. El Capitan looks down on a river that winds through Yosemite. What is the river’s name?
  3. In the WWDC keynote, Tim Cook showed off a list of demands some Cleveland Indians players were using to ransom their teammate’s 100th home run ball. What item did Apple carefully remove from the list?
  4. With WebKit already using WK, WatchKit had to find a different class prefix. What is the unusual prefix used for the most of the WatchKit framework?
  5. The name “Swift” can be written using a ligature for its final two letters. What are the five Unicode-standard ligatures beginning with the letter “f”?
  6. The typeface used for Apple Watch (and the new versions of iOS and OS X) is “San Francisco,” but it isn’t the first custom font Apple has used by that name. What were the letters of the original “San Francisco” meant to resemble? For a bonus point, name the original font’s designer.
  7. What is reportedly the lock screen image on Jony Ive’s iPhone?
  8. Apple made a splash when they announced that ResearchKit would be open source and hosted on GitHub. What was the first pull request accepted for ResearchKit?
  9. ResearchKit also uses an unexpected class prefix. What is the prefix and what does it stand for?
  10. Scott Forstall is back in the news, producing a Broadway musical that just won five Tonys. What is the name of the musical? For a bonus point, upon what author’s memoir is the musical based?

Round 2: Name That Framework

How well do you know Cocoa? For each question in this round, you’ll be given three classes with their identifying prefix removed. Name the framework which contains all three.

  1. MultiPoint, Placemark, Polyline
  2. Locale, NotificationCenter, NumberFormatter
  3. Correlation, Statistics, Unit
  4. Navigation, Preferences, UserScript
  5. Switch, Timer, Map
  6. URL, URLCache, URLCredential
  7. Activity, Lexicon, DictationPhrase
  8. ContentItem, MoviePlayerController, RemoteCommand
  9. PaymentToken, PaymentMethod, ShippingMethod
  10. Beacon, Floor, Visit

Round 3: Picture Round

  1. Who is shown here sporting this unannounced gold link bracelet Apple Watch shortly before launch?Picture 1

  2. What TV show featured these watches? For a bonus point, what was the related catchphrase?Picture 2

  3. Hailing from the same era, what development tool is this?Picture 3

  4. What Apple Design Award-winning app is this?Picture 4

  5. What Apple Design Award-winning app is this?Picture 5

  6. What app is this?Picture 6

  7. What app is this?Picture 7

  8. Who is this?Picture 8

  9. Who is this?Picture 9

  10. What are the Unicode names for these Emoji?Picture 10

Round 4: Anagrammable

NSAnagram has been ported to Swift as Anagrammable, still a vexing test of knowledge and concentration. Each question is an anagram, whose letters can be rearranged to form the name of a type or protocol in the Swift standard library. Good luck!

For timing, listen to these three songs play back to back:




  1. Be Loud!
  2. Forget No Ear
  3. Too Plain
  4. Oboe Penalty
  5. Scalable Lube Item
  6. Poets Win At Poetry
  7. Ol’ Potty Licence
  8. Unprofitable Tea Menus
  9. Ram Placebo
  10. Tin?

Answers

Round 1: General Knowledge

  1. Star Trek V: The Final Frontier
  2. Merced River
  3. 50 gallon drum of lube
  4. WKInterface
  5. ff, fi, fl, ffi, ffl
  6. A ransom note, by Susan Kare
  7. A Playmobile figure of himself
  8. A typo in the README.md
  9. ORK: Open Research Kit
  10. Fun Home, based on the memoir by Alison Bechdel

Round 2: Name That Framework

  1. MapKit
  2. Foundation or CoreFoundation (2 points for both)
  3. HealthKit
  4. WebKit
  5. WatchKit
  6. Foundation
  7. UIKit
  8. MediaPlayer
  9. PassKit
  10. CoreLocation

Round 3: Picture Round

  1. Beyonce
  2. Parker Lewis Can’t Lose, “Synchronize Swatches”
  3. ResEdit
  4. Metamorphabet
  5. Workflow
  6. Meerkat
  7. GIFs
  8. Chris Lattner
  9. Christian Laettner
  10. Aubergine, Dancer, Clinking Beer Mugs

Round 4: Anagrammable

  1. Double! (2 points if marked as an implicitly unwrapped optional)
  2. GeneratorOf
  3. Optional
  4. BooleanType
  5. MutableSliceable
  6. RawOptionSetType
  7. CollectionType
  8. UnsafeMutablePointer
  9. Comparable
  10. Int? (2 points if marked as an Optional)

Well, how did you do this time? Tweet out your score to see how you stack up to your peers!

iOS 9

$
0
0

WWDC 2015 may not have packed quite as many fireworks as its predecessor, but neither was it short on the new and shiny. The introduction of watchOS 2, including a revamped WatchKit, access to the Apple Watch hardware, and support for complications. Major changes to the Swift language and the announcement of open source plans. Brand new frameworks, such as Contacts, ContactsUI, and CoreSpotlight, and new UIKit types like UIStackView and SFSafariViewController.

We’ll surely delve into these major new components in the weeks and months to come. For now, however, let’s take a look at some of the smaller changes that iOS 9 brings to the APIs we already know and love.


String Transformations

Up first is the news that string transformations, formerly housed in Core Foundation, have made their way to NSString and the Swift String type. This is a huge advance in discoverability and ease-of-use for this powerful Cocoa feature, because there is no longer any need to deal with the hassle of bridging to and from CFStringRef. Here’s how some of our favorite transformations can be done along with the new NSStringTransform* constants that enable them:

Transliteration

"privet".stringByApplyingTransform(NSStringTransformLatinToCyrillic,reverse:false)// "привет""안녕하세요".stringByApplyingTransform(NSStringTransformLatinToHangul,reverse:true)// "annyeonghaseyo""annyeonghaseyo".stringByApplyingTransform(NSStringTransformLatinToHangul,reverse:false)// "안녕하세요"
NSLog(@"%@",[@"privet"stringByApplyingTransform:NSStringTransformLatinToCyrillicreverse:NO]);// "привет"NSLog(@"%@",[@"annyeonghaseyo"stringByApplyingTransform:NSStringTransformLatinToHangulreverse:NO]);// "안녕하세요"NSLog(@"%@",[@"안녕하세요"stringByApplyingTransform:NSStringTransformLatinToHangulreverse:YES]);// "annyeonghaseyo"

Unicode Names

"🐷".stringByApplyingTransform(NSStringTransformToUnicodeName,reverse:false)// "{PIG FACE}"
NSLog(@"%@",[@"🐷"stringByApplyingTransform:NSStringTransformToUnicodeNamereverse:NO]);// "{PIG FACE}"

Normalizing User Input

"Hello! こんにちは! สวัสดี! مرحبا! 您好!".stringByApplyingTransform(NSStringTransformToLatin,reverse:false)?.stringByApplyingTransform(NSStringTransformStripDiacritics,reverse:false)?.localizedLowercaseString.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceCharacterSet())// ["hello!", "kon'nichiha!", "swasdi!", "mrhba!", "nin", "hao!"]
NSString*input=@"Hello! こんにちは! สวัสดี! مرحبا! 您好!";NSString*processing=[inputstringByApplyingTransform:NSStringTransformToLatinreverse:NO];processing=[processingstringByApplyingTransform:NSStringTransformStripDiacriticsreverse:NO];NSArray<NSString*>*output=[processing.localizedLowercaseStringcomponentsSeparatedByCharactersInSet:[NSCharacterSetwhitespaceCharacterSet]];NSLog(@"%@",output);// ["hello!", "kon'nichiha!", "swasdi!", "mrhba!", "nin", "hao!"]

For more on string transformations, be sure to check out Mattt’s terrific article on CFStringTransform.

CLLocationManager.requestLocation

Core Location includes a nice new API for apps that simply need to fetch the user’s location without continuous location updates. requestLocation() uses the same delegate methods as continuous updates, turning itself off after delivering the location with the desired accuracy:

classViewController:UIViewController,CLLocationManagerDelegate{letlocationManager=CLLocationManager()// ...overridefuncviewDidLoad(){super.viewDidLoad()locationManager.delegate=selflocationManager.desiredAccuracy=kCLLocationAccuracyHundredMeterslocationManager.requestLocation()}// MARK: - CLLocationManagerDelegatefunclocationManager(manager:CLLocationManager,didUpdateLocationslocations:[CLLocation]){ifletlocation=locations.first{print("Current location: \(location)")}else{// ...}}funclocationManager(manager:CLLocationManager,didFailWithErrorerror:NSError){print("Error finding location: \(error.localizedDescription)")}}

Swiftification

The Cocoa APIs in iOS 9 (and OS X 10.11) include thousands of minor changes designed to make Swift interoperability safer and cleaner. These changes start with the familiar nullability annotations, converting implicitly unwrapped parameters and return values to either true Optionals or simple, non-optional data types. But they also go much further.

For example, instead of marking NSArray return values as nullable, many APIs have been modified to return an empty array—semantically these have the same value (i.e., nothing), but a non-optional array is far simpler to work with. Moreover, many Cocoa APIs are gradually taking advantage of the new Objective-C generic syntax to provide typed arrays. The CLLocationManagerDelegate method locationManager(_:didUpdateLocations:) shown above is one such example: where the locations parameter used to be imported as an AnyObject array, it is now an array of CLLocation, eliminating the need for any casting in the method body.

Finally, some APIs that were completely inaccessible from Swift have been revised, such as methods for retrieving UIAppearance proxies that limit appearance to a particular containment hierarchy—UIKit’s version of CSS-lite. The old appearanceWhenContainedIn: method is implemented with C variadic parameters, which Swift doesn’t import; the new appearanceWhenContainedInInstancesOfClasses(_:) method simply takes an array of type objects:

UIBarButtonItem.appearanceWhenContainedInInstancesOfClasses([UINavigationController.self]).tintColor=UIColor.redColor()
[UIBarButtonItemappearanceWhenContainedInInstancesOfClasses:@[[UINavigationControllerclass]]].tintColor=[UIColorredColor];

Ironically enough, this method crashes at runtime when used from Swift. Betas gonna beta.

NSFormatter Additions

The new Contacts framework includes NSFormatter subclasses for localized formatting of contacts and addresses alongside a new Foundation NSPersonNameComponentsFormatter class. We’ll cover those more in the weeks to come, but here let’s highlight a few additions to two old favorites: NSNumberFormatter and NSDateFormatter.

NSNumberFormatter

First, NSNumberFormatter sees four additional styles in iOS 9, starting with .OrdinalStyle, used for converting numbers to their ordinal equivalent:

letformatter=NSNumberFormatter()formatter.numberStyle=.OrdinalStyleletnumbers=[1,2,3,4,5]numbers.map{formatter.stringFromNumber($0)!}// ["1st", "2nd", "3rd", "4th", "5th"]formatter.locale=NSLocale(localeIdentifier:"es")numbers.map{formatter.stringFromNumber($0)!}// ["1º", "2º", "3º", "4º", "5º"]
NSNumberFormatter*formatter=[[NSNumberFormatteralloc]init];formatter.numberStyle=NSNumberFormatterOrdinalStyle;NSArray<NSNumber*>*numbers=@[@1,@2,@3,@4,@5];for(NSNumber*numberinnumbers){NSLog(@"%@",[formatterstringFromNumber:number]);}// "1st", "2nd", "3rd", "4th", "5th"formatter.locale=[NSLocalelocaleWithLocaleIdentifier:@"es"];for(NSNumber*numberinnumbers){NSLog(@"%@",[formatterstringFromNumber:number]);}// "1º", "2º", "3º", "4º", "5º"

Next, the existing .CurrencyStyle gets some company with .CurrencyPluralStyle, .CurrencyISOCodeStyle, and .CurrencyAccountingStyle. When using these new styles, be sure your locale fully specifies both a language and a country, which it makes it possible for the formatter to choose the right currency and presentation:

letstyles:[NSNumberFormatterStyle]=[.CurrencyStyle,.CurrencyPluralStyle,.CurrencyISOCodeStyle,.CurrencyAccountingStyle]formatter.locale=NSLocale(localeIdentifier:"en_US")styles.map{formatter.numberStyle=$0returnformatter.stringFromNumber(-125)!}// ["-$125.00", "-125.00 US dollars", "-USD125.00", "($125.00)"]formatter.locale=NSLocale(localeIdentifier:"es_ES")styles.map{formatter.numberStyle=$0returnformatter.stringFromNumber(-125)!}// ["-125,00 €", "-125,00 euros", "-125,00 EUR", "-125,00 €"]

NSDateFormatter

Second—and I’ll fess up—this new NSDateFormatter method is a bit of a cheat. setLocalizedDateFormatFromTemplate(_:) was introduced in iOS 8 but largely slid under the radar until this year’s sessions on internationalization. This new-ish method makes it supremely easy to define a template for the date and time elements you want; however, it leaves the formatting up to the excellent localization built into NSDateFormatter:

letnow=NSDate()// full date and timeletfullFormatter=NSDateFormatter()fullFormatter.setLocalizedDateFormatFromTemplate("yyyyMMMMddhhmm")// month name and year onlyletshortFormatter=NSDateFormatter()shortFormatter.setLocalizedDateFormatFromTemplate("yyMMMM")fullFormatter.stringFromDate(now)// "June 23, 2015, 4:56 PM"shortFormatter.stringFromDate(now)// "June 15"

If you switch locales, you’ll need to reset the localized date format to get the correct template for the new locale:

fullFormatter.locale=NSLocale(localeIdentifier:"de_DE")fullFormatter.setLocalizedDateFormatFromTemplate("yyyyMMMMddhhmm")shortFormatter.locale=NSLocale(localeIdentifier:"de_DE")shortFormatter.setLocalizedDateFormatFromTemplate("yyMMMM")fullFormatter.stringFromDate(now)// "23. Juni 2015, 4:56 nachm."shortFormatter.stringFromDate(now)// "Juni 15"

Well, that’s that for our quick tour through some of iOS 9’s new APIs, though there are many more where those came from. What new features are you most excited about in iOS 9 or OS X 10.11? Check out Apple’s diffs and let us know!

CloudKit

$
0
0

As an iOS developer, if you want to make an application on your own, you sometimes need to write back-end code. Even for the developer who can take that on, there is more than just the code, there’s also maintenance. Your worst fear becomes not that people might not like your application, but that your server might fail under heavy traffic.

Fortunately, we now have CloudKit. Apple takes care of all these details, so you can focus on how to make your application great.

What is CloudKit?

Perhaps you’ve heard of iCloud Drive before—iCloud Drive is where we can store our user’s data and files for easy access from other devices. CloudKit is the framework that helps us do this easily in the apps we create.

CloudKit offers tons of APIs to access iCloud. You can create a user model inside your application linked to a user’s iCloud account. Meanwhile, you can have a public global database to store application-level data. You can also save large files and bulk data into iCloud Drive, so your users can use their data from their other devices. This works just like working on local files, but with all the operations sent to the cloud.

Overall, CloudKit is a framework that replaces back-end web services like old-school databases, file storage, and user authentication systems. With CloudKit’s help you don’t need to worry about any of these, so you can focus your energy on your application.

Get into CloudKit

Imagine that you’re working on a check-in application where users can add “places” with their location and check in at these places. We’ll talk about how to build some basic functions of the check-in application with CloudKit.

Enable CloudKit

We have already talked about how powerful CloudKit is, now it is the time to show you how to use it. It’s simple. All you need is to turn on iCloud and check CloudKit in the project panel of Xcode:

Enabling CloudKit in Xcode

Fundamental CloudKit Objects

There are 7 different fundamental objects in CloudKit. You may have seen this elsewhere in your programming career, but there are some slight differences.

  • CKContainer: A container is like a sandbox. An application can only use the resources inside its container. The container is located at the very outer border and each application has one and only one separate container. (You can allow other applications to access your container by configuring CloudKit Dashboard.)

  • CKDatabase: A database is the place that you put all your data. There are two different kinds of databases: private and public. The private database is where you store sensitive data, like user’s information. The public database is where you store shared data. For example, in our check-in application, you would store a user’s birthday and check-ins in the private database but store “places” information in the public database.

  • CKRecord: A record is a piece of data inside your database. It is stored as a key-value pair. For now, you can save NSString, NSNumber, NSData, NSDate, CLLocation, CKReference, and CKAsset, as well as arrays of all the types listed above.

  • CKRecordZone: Records are not stored scattered in a database, they are located in record zones. Every application has a default record zone, and you can also have your own custom record zones.

  • CKRecordIdentifier: the unique label of a record, used for locating a particular record.

  • CKReference: Reference is like the relationship in an RDBMS. In our check-in example, there may be many people checked in at the same place, so we’ll need to establish a reference between places and check-ins.

  • CKAsset: Assets are resources, like binary files or bulk data. For example, a user’s picture should be stored as an asset.

Convenience API

CloudKit’s convenience API is there to do basic operations such as reading, writing, and editing records.

Let’s work on our check-in application. To get started, import the CloudKit framework and get a reference to the public database:

importCloudKit// ...letpublicDB=CKContainer.defaultContainer().publicCloudDatabase
#import <CloudKit/CloudKit.h>// ...CKDatabase*publicDB=[[CKContainerdefaultContainer]publicCloudDatabase];

Next, create a new place and save it:

letgreatID=CKRecordID(recordName:"GreatPlace")letplace=CKRecord(recordType:"Place",recordID:greatID)publicDB.saveRecord(place){savedRecord,errorin// handle errors here}
CKRecordID*greatID=[[CKRecordIDalloc]initWithRecordName:@"GreatPlace"];CKRecord*place=[[CKRecordalloc]initWithRecordType:@"Place"recordID:greatID];[publicDBsaveRecord:placecompletionHandler:^(CKRecord*savedPlace,NSError*error){// handle errors here}];

CloudKit will connect to the Internet asynchronously when saveRecord:completionHandler: method is invoked. Remember to handle the error in the block, since the user’s connection may be unstable. A good application deserves perfect error handling logic.

You should check the error code of the NSError object to detect which kind of error you are dealing with. A CKErrorNetworkUnavailable error may occur if you were on a bad internet connection, and what you need to do is to retry the operation after failure. But when to retry? Immediately or 10 seconds later? Don’t worry, CloudKit offers a suggestion in the error’s userInfo dictionary with the key CKErrorRetryAfterKey:

ifletretryAfterValue=error.userInfo[CKErrorRetryAfterKey]as?NSTimeInterval{letretryAfterDate=NSDate(timeIntervalSinceNow:retryAfterValue)// ...}
doubleretryAfterValue=[error.userInfo[CKErrorRetryAfterKey]doubleValue];NSDate*retryAfterDate=[NSDatedateWithTimeIntervalSinceNow:retryAfterValue];

Here I’ll read the place’s information back:

letgreatID=CKRecordID(recordName:"GreatPlace")publicDB.fetchRecordWithID(greatID){fetchedPlace,errorin// handle errors here}
CKRecordID*greatID=[[CKRecordIDalloc]initWithRecordName:@"GreatPlace"];[publicDBfetchRecordWithID:greatIDcompletionHandler:^(CKRecord*fetchedPlace,NSError*error){// handle errors here}];

And here I’ll edit an existing place’s information:

letgreatID=CKRecordID(recordName:"GreatPlace")publicDB.fetchRecordWithID(greatID){fetchedPlace,erroringuardletfetchedPlace=fetchedPlaceelse{// handle errors herereturn}letname=fetchedPlace["name"]as?String??"Unnamed Place"fetchedPlace["name"]=name+" Door A"publicDB.saveRecord(fetchedPlace){savedPlace,savedErrorin//...}}
CKRecordID*greatID=[[CKRecordIDalloc]initWithRecordName:@"GreatPlace"];[publicDBfetchRecordWithID:greatIDcompletionHandler:^(CKRecord*fetchedPlace,NSError*error){if(fetchedPlace!=nil){NSString*name=fetchedPlace[@"name"];fetchedPlace[@"name"]=[namestringByAppendingString:@" Door A"];[publicDBsaveRecord:fetchedPlacecompletionHandler:^(CKRecord*savedPlace,NSError*savedError){//...}];}else{// handle errors here}}];

The progress of editing a record is pretty simple: read, edit, then save. What you should really pay attention to is how to do the three-step updating process, especially when updating one record depends on fetching others.

A bad practice:

database.fetchRecordWithID(recordID,completionHandler:{record,errorin//...database.fetchRecordWithID(otherRecordID,completionHandler:{otherRecord,otherErrorin//...database.saveRecord(record!,completionHandler:{anotherRecord,anotherErrorin//...})})})
[databasefetchRecordWithID:recordIDcompletionHandler:^(CKRecord*record,NSError*error){//...[databasefetchRecordWithID:otherRecordIDcompletionHandler:^(CKRecord*otherRecord,NSError*otherError){//...[databasesaveRecord:recordcompletionHandler:^(CKRecord*anotherRecord,NSError*anotherError){//...}];}];}];

With very complex nested operations you may run into a dilemma: There are three (or more) blocks and three (or more) errors to handle, so where should you handle the errors? where should you retry the operation if an error occurs? All together it starts looking like kind of a disaster.

A better approach is to use NSOperation dependencies to manage the dependent tasks:

letfirstFetch=CKFetchRecordsOperation()letsecondFetch=CKFetchRecordsOperation()secondFetch.addDependency(firstFetch)letqueue=NSOperationQueue()queue.addOperations([firstFetch,secondFetch],waitUntilFinished:false)
CKFetchRecordsOperation*firstFetch=...;CKFetchRecordsOperation*secondFetch=...;[secondFetchaddDependency:firstFetch];NSOperationQueue*queue=[[NSOperationQueuealloc]init];[queueaddOperations:[firstFetch,secondFetch]waitUntilFinished:NO];

You can finish almost all the work you need to do with the convenience API. What do you think so far? It’s much easier than writing backend code, maintaining a server, and writing the code to communicate with it.

Advanced Features

Queries

While powerful, the convenience APIs aren’t quite enough to finish our check-in application—now it’s time to add search functionality. To add a search function, you will need a query. A CKQuery object is made up of RecordType, NSPredicate and NSSortDescriptors.

NSPredicate plays an important role here, handling string matching, location and date ranging, and combinations of simple queries. Refer to the CKQuery documentation for more.

Let’s say I want all places containing the name ‘Apple Store’:

letpredicate=NSPredicate(format:"name CONTAINS 'Apple Store'")letquery=CKQuery(recordType:"Place",predicate:predicate)publicDB.performQuery(query,inZoneWithID:nil){results,errorin// ...}
NSPredicate*predicate=[NSPredicatepredicateWithFormat:@"name CONTAINS 'Apple Store'"];CKQuery*query=[[CKQueryalloc]initWithRecordType:@"Place"predicate:predicate];[publicDBperformQuery:queryinZoneWithID:nilcompletionHandler:^(NSArray*results,NSError*error){// ...}];

Alternately, you could modify the query to retrieve all the places within one mile around the user.

Subscriptions

After adding queries, our application is almost complete. Or wait, did we forget something?

Yes: notifications. They’re a critical part of any check-in application.

For example, a social person may want to be notified if someone mentions “party” around him or her. This is possible with CloudKit—the framework already provides something to achieve this using the CKSubscription class:

letpredicate=NSPredicate(format:"description CONTAINS 'party'")letsubscription=CKSubscription(recordType:"Checkin",predicate:predicate,options:.FiresOnRecordCreation)letinfo=CKNotificationInfo()info.alertLocalizationKey="NEW_PARTY_ALERT_KEY"info.soundName="NewAlert.aiff"info.shouldBadge=truesubscription.notificationInfo=infopublicDB.saveSubscription(subscription){subscription,errorin//...}
CKDatabase*publicDB=[[CKContainerdefaultContainer]publicCloudDatabase];NSPredicate*predicate=[NSPredicatepredicateWithFormat:@"description CONTAINS 'party'"];CKSubscription*subscription=[[CKSubscriptionalloc]initWithRecordType:@"Checkin"predicate:predicateoptions:CKSubscriptionOptionsFiresOnRecordCreation];CKNotificationInfo*info=[CKNotificationInfonew];info.alertLocalizationKey=@"NEW_PARTY_ALERT_KEY";info.soundName=@"NewAlert.aiff";info.shouldBadge=YES;subscription.notificationInfo=info;[publicDBsaveSubscription:subscriptioncompletionHandler:^(CKSubscription*subscription,NSError*error){//...}];

Receiving the notification is handled by the application delegate:

funcapplication(application:UIApplication,didReceiveRemoteNotificationuserInfo:[NSObject:AnyObject]){letckNotification=CKNotification(fromRemoteNotificationDictionary:userInfoas![String:NSObject])ifckNotification.notificationType==.Query,letqueryNotification=ckNotificationas?CKQueryNotification{letrecordID=queryNotification.recordID//...}}
-(void)application:(UIApplication*)applicationdidReceiveRemoteNotification:(NSDictionary*)userInfo{CKNotification*ckNotification=[CKNotificationnotificationFromRemoteNotificationDictionary:userInfo];if(ckNotification.notificationType==CKNotificationTypeQuery){CKQueryNotification*queryNotification=ckNotification;CKRecordID*recordID=[queryNotificationrecordID];// ...}}

More

As I said in the beginning, CloudKit can do much more than described in this article. You can allow your users to add pictures to their check-ins. References in CloudKit allow you to get all the related check-ins for certain places. Moreover, CloudKit has an API that allows you to find your users' friends who are also using your application via their address book.

Can’t wait to try out CloudKit? It could free you from writing backend code, caring about server pressure, maintaining a large CDN network, renting a server, and more. But wait—what about the price? How much does it cost? The answer is: free. Apple allows using CloudKit for 10 GB of resource storage, 100 MB of data storage, and 2 GB of daily transfer, scaling with your user base up to to 1 petabyte of resources, 10 TB database, and 200 TB transfer.

Check out the CloudKit cost calculator at the bottom of the page for detailed free limits and pricing.


As of WWDC 2015, CloudKit is not only available on iOS or OS X. You can now integrate CloudKit JS with your website to make it possible for iCloud users to enjoy your service in a web browser or use the CloudKit web service to communicate with CloudKit servers directly via HTTP request. All this means it’s now possible to use CloudKit from any other mobile or desktop platform!

CloudKit is an amazing thing. I can’t wait to see the awesome applications you NSHipsters make with it.

Viewing all 71 articles
Browse latest View live