Skip to main content

Posts

Showing posts from July, 2015

Swift 2.0: More crashing and throwing in Aldwych (a JSON Parser)

A conversation started on twitter yesterday surrounding the inability of subscripts to throw errors. It was begun by @krzyzanowskim and gave me the opportunity to think even further about the approach to error handling I am employing in Aldwych 2.0 (a JSON parser for Swift).
Standard approach My standard approach is to follow the Swift standard library way of doing things as much as possible. The core example being to throw errors when something user-led might not be possible: e.g. a file chosen is of the wrong type or the data in the file is corrupted, or the data simply doesn't parse.

This logic means that NSJSONSerialization has throwing methods as standard for creating objects from JSON and for creating JSON from objects. While NSData goes halfway and has a choice of failable initializers and throwing intializers in iOS 9 (Xcode 7 beta 4). For example:
init(contentsOfURL url: NSURL, options readOptionsMask: NSDataReadingOptions) throws and
init?(contentsOfURL url: NSURL) And …

Swift 2.0: throwing vs failing vs crashing vs bool

Updating Aldwych (a JSON parser for Swift), I wrote a method for changing a value in a dictionary that closely echoes the standard library but which has one important parameter added: typesafe.
public mutating func updateValue(value:AnyObject, forKey key:String, typesafe:Bool = true) So what happens is that if typesafe is set to false any type can be exchanged for any (JSON compatible type) but if typesafe is set to its default (true) and we try to set a different type from the current one then the value won't be updated (unless it was null).

A similar thing happened in Aldwych 1.0, but that was before Swift gained error do-try-catch functionality. There an attempt to change types in typesafe mode resulted in silent failure. The update didn't happen but there was no way of knowing this without checking.
When throwing and catching doesn't fit With the new ability to throw and catch errors it seemed at first an ideal solution for Aldwych's type safety that an error sho…

Updating Aldwych (Part 1): Parsing JSON with recursive enums in Swift

The purpose of Aldwych from the very beginning has been to provide JSON parsing that is type safe, flexible and familiar. And when recursive enums were first announced by Chris Lattner at WWDC 2015, I hoped they would enable a great internal simplification of the JSON parser.
Step One With this hope in mind, and with a handkerchief filled with sandwiches tied to a stick, I decided to experiment with recursive enums by making the core type in Aldwych simply this:
public enum JSONValue { case JString(String), Number(NSNumber), JBool(Bool), Null indirect case JArray([JSONValue]), JDictionary([String:JSONValue]) } which was a pretty good start but I encountered one very particular problem: the for-in loop. If you think about an Array we loop through it using for v in array {} but in a Dictionary we use for (k,v) in dictionary {}. This means that the Element type of an Array is a single value while that of a Dictionary is a tuple.

This was the first hurdle because a Ge…

Swift: What do I understand about flatMap? (updated 27 July 2015)

Sometimes you read a blogpost and it is only by responding to the blogpost that you come to an understanding of your own understanding. I've written a lot about fumbling with flatMap, but it wasn't until I read Natasha the Robot's recent post (and saw it evolve in response to comments) that I brought all those things together into a list of what I currently understand about flatMap. And once I'd noted down what I knew about flatMap, I suddenly became scared that I might forget what I currently know about flatMap, so I'm reproducing the comment I made here.
Comment So far I've come to the following understandings:

1. it [i.e. flatMap] can be used to reduce an array of optionals to non-optionals, e.g. [String?] to [String], as you've done here [in the post]

2. it can reduce nested arrays into a single array, e.g. [[1,2,3],[4,5,6]] to [1,2,3,4,5,6]

3. it works at a level one deeper than map (as seen in point 2), which means that if you pass it an array tha…

Deferring and Delegating in Swift 2 (Xcode 7 beta 3) - updated

We're used to the Cocoa framework having classes that are assigned delegates from actions such as XML parsing. But what if we want to create our own types with our own delegates.
protocol Main { var delegate:Delegate {get set} } protocol Delegate { func started() func finished() } The above code defines a simple delegate relationship using protocols. There then follows two types that fulfil these protocols:
struct MyMain: Main { var delegate:Delegate func doSomething() { delegate.started() print(1+1) delegate.finished() } } struct MyDelegate: Delegate { func started() { print("it's started") } func finished() { print("it's finished") } } As long as the main type is assigned a delegate it fulfils the protocol but the delegate itself must have started() and finished() methods because they are outlined in the delegate protocol. The doSomething() method in the main type cou…

UIActivityViewController (Part 2): Building a custom UIActivity ("Open In...") in Swift

Building a Custom UIActivity You'll notice that there was a parameter that was ignored in the last part of this series when creating and presenting a UIActivityViewController and that was applicationActivities, which was always being set to nil. It's important to note the parameter doesn't specify the built-in activity types to display, which are all included at instantiation (and must be subsequently excluded where required), but instead enables custom UIActivity instances to be included.
Custom activities are created by subclassing UIActivity and overriding the following methods: activityType -> String?activityTitle  -> String?activityImage  -> UIImage?canPerformWithActivityItems: -> Bool prepareWithActivityItems:activityCategory -> UIActivityCategoryactivityViewController -> UIViewController?performActivity Half of the methods return optionals and the final two are an either/or choice. The type, title and image methods set the text and the appearance o…

UIDocumentInteractionController and Swift: Two rules to never forget

A UIDocumentInteractionController is used to enable the sharing of documents between your app and other apps installed on a user's device. It is simple to set up as long as you remember two rules:
Always make the UIDocumentInteractionController instance a class (type) property. If you only retain a reference to the controller for the life of the method that is triggered by the button press your app will crash.Configure the UIDocumentInteractionController before the button calling the method is pressed so that there is not a wait in which the app is waiting for the popover to appear. The second "rule" is applied because while the presentation of the controller happens asynchronously, the instantiation does not. And you may find that there is a noticeable delay to open the popover if you throw all the code for instantiation and presentation inside a single method called on the press of a button.

Note: If you're dealing with a document that is being continuously saved t…

UIActivityViewController (Part 1): Tweeting and Printing in Swift

If you've read recent posts on this blog about the presentation of popovers then you'll be familiar with the approach of accessing a UIPopoverPresentationController. The only difference with UIActivityViewController is that there are fixed requirements for this class:
On iPad, you must present the view controller in a popover. On iPhone and iPod touch, you must present it modally. But not only is this a requirement, it is a default. And this can be demonstrated to be true by placing the following code in the viewDidLoad method of a view controller and running:
let str = "String" let activityController = UIActivityViewController(activityItems: [str], applicationActivities: nil) switch activityController.modalPresentationStyle { case .FullScreen: print("Full") case .PageSheet: print("Page") case .FormSheet: print("Form") case .CurrentContext: print("Current") case .Custom: …

The Wonderful World of Popups and Popovers in Swift: Beyond the Newly Deprecated

The Wonderful World of Popups and Popovers in Swift To those approaching iOS alerts and popovers for the first time, or perhaps after a break, things can be a bit mind boggling. The docs tell you to use a UIPopoverController to present a UIImagePickerController, but the UIPopoverController docs tell you that it has been deprecated in iOS 9 and to use UIPopoverPresentationController instead. But a view controller doesn't recognise a UIPopoverPresentationController as a view controller, so it can't present it using its presentation method. Argh!

Finally, you get your head around the logic of UIPopoverPresentationController and then you want to figure out how to display a UIAlertView, but that was deprecated in iOS 8. So you use UIAlertViewController with a style of UIAlertControllerStyleAlert, which turns out to actually need to be written UIAlertControllerStyle.Alert in Swift.

But actually you don't want an alert in the centre of the screen, you want it to popover from a b…

The ABC of Making a UIAlertViewController Popover in Swift (Xcode 7 beta 2; iOS 9)

Last time we looked at making a UIImagePickerController popover, and this time we do something very similar but slightly different. We start by creating a UIAlertController instance:
let distributionAlertController = UIAlertController(title: "Distribution", message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet) Note here the use of preferred style UIAlertControllerStyle.ActionSheet rather than .Alert. Next we want to add an action to the alert, which happens like this:
// create the action let fill = UIAlertAction(title: "Fill", style: UIAlertActionStyle.Default, handler: {[unowned self] a in self.stackView.distribution = UIStackViewDistribution.Fill; self.distributionAlertController.dismissViewControllerAnimated(true, completion: nil)}) // add the action distributionAlertController.addAction(fill) You can add as many actions as you like (within reason of course!).

Note: The example assumes the use of a UIStackView called stackView.
Calling the alert …

Swift: Displaying a UIImagePickerController in iOS 9 using non-deprecated classes

In iOS there have been so many classes come and go for the presentation of alerts and actions, and there's so much documentation (and so many tutorials) that point to deprecated approaches, that it can be a bit mind boggling where to start when the compiler presents you with a warning. And this is made even more difficult by many deprecated classes having very similar names to newer or non-deprecated classes for doing similar things. So here's the latest way to perform a common task: presenting an image picker.
The old way We'll start with the old, deprecated, way of displaying a UIImagePickerController first:
@IBAction func selectImage(sender: AnyObject) { let imgPicker = UIImagePickerController() imgPicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary let popper = UIPopoverController(contentViewController: imgPicker) popper.presentPopoverFromBarButtonItem(sender as! UIBarButtonItem, permittedArrowDirections: UIPopoverArrowDirecti…

Swift: Common Auto Layout scenarios for UIStackView

If you are using content with an intrinsic size (e.g. a collection of UIImageViews), then you are likely to want to allow a UIStackView to freely expand around the content. In order to do this I think there are only really a limited set of common scenarios, which can be very simply divided into two.
A Centred UIStackView The first one is to pin it to the top layout guide and to centre on the X-axis: // top constraint let topConst = NSLayoutConstraint(item: stackView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem:topLayoutGuide, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0) // centre constraint let centerConst = NSLayoutConstraint(item: stackView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem:view, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0) NSLayoutConstraint.activateConstraints([topConst,centerConst]) And here's the alternative code for this (using Anchors):
let to…

Fear and Loathing in Auto Layout: Programmatic Constraints

I want to start this post with a brief list of points that are often skipped over in tutorials and I think might be useful to people seeking answers:
Setting constraints programmatically you must set all subviews to subView.translatesAutoresizingMaskIntoConstraints = false (but not self.view). But this rule doesn't apply to views added to a UIStackView (although it does apply to the top level UIStackView).The metrics parameter inside the NSLayoutConstraint.constraintsWithVisualFormat() type method, which most tutorials set to nil is a dictionary that can be used instead of placing numbers directly into the strings. For example, we might have a key called "spacing" and set its value to 20 inside the metrics dictionary. Now instead of writing 20 in a visual format string we can write "spacing".If you want to work with multipliers then you'll need to use the regular NSLayoutConstraint initializer. Visual Format Language is of no use here (unless you want to re…