Where technology meets something or other


Erica Sadun. iPhone. iPod touch. Macintosh. and More.

Contact

erica at ericasadun.com

Meta

  1. RSS
  2. admin
  3. valid XHTML

Auto Layout: iOS 81 Comment

erica | 1:34 pm | August 28, 2014 | Development,iOS,OS X,Various Frustrations,Xcode

It’s been a pretty exciting summer as far as Auto Layout goes. I’m busy going over material so I can get some dates and work estimates to Trina on a possible 3rd edition of Auto Layout. Between Swift, OSX, iOS 8, and whatever is going to be announced in September, it looks like a particularly interesting place to be.

I can’t tell you how thrilled I am about active, the property that self-installs and removes constraints to their natural destination. I submitted my first radar on this back before the first edition was even published. Now with the third edition, I suppose I’ll be all “Yeah, that’s my radar baby!”

The long iOS 8 summer first gave us left and right layout guides, a la the top and bottom guides we first encountered in iOS 7 but they soon disappeared and have since been replaced by a suite of Margin-based layout attributes:

    NSLayoutAttributeLeftMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeRightMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeTopMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeBottomMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeLeadingMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeTrailingMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeCenterXWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeCenterYWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),

Comments and properties in the UIView header file indicate a layout tree of margins. I think it’s fair to assume this ties into the adaptive application that runs properly both on full-screen as well as side-by-side.

/*
 -layoutMargins returns a set of insets from the edge of the view's bounds that denote a default spacing for laying out content.
 If preservesSuperviewLayoutMargins is YES, margins cascade down the view tree, adjusting for geometry offsets, so that setting the left value of layoutMargins on a superview will affect the left value of layoutMargins for subviews positioned close to the left edge of their superview's bounds
 If your view subclass uses layoutMargins in its layout or drawing, override -layoutMarginsDidChange in order to refresh your view if the margins change.
 */
@property (nonatomic) UIEdgeInsets layoutMargins NS_AVAILABLE_IOS(8_0);
@property (nonatomic) BOOL preservesSuperviewLayoutMargins NS_AVAILABLE_IOS(8_0); // default is NO - set to enable pass-through or cascading behavior of margins from this view’s parent to its children
- (void)layoutMarginsDidChange NS_AVAILABLE_IOS(8_0);

Unfortunately, the material from WWDC is light on details and these updates didn’t take place until fairly recent betas. Got any insights into how this material will play out? I’d love to hear it. (And thanks in advance!)


Swift: Embettering solutions1 Comment

erica | 12:00 pm | August 27, 2014 | Development,Swift

With Swift, there’s almost always a better way to do things and when you get to that better way, it just rings with “of course”-ness.

As usual, this started as a question from a participant in #swift-dev. “This doesn’t work,” he said, and pasted the following.

func continueGame() {
    if self.gameLogic.count == 0 {
        return
    }
    self.gameLogic[0]()
    self.gameLogic.removeAtIndex(0)
}

So I started kicking the wheels on it. To get going, I decided to use the following array of closures to test my approaches.

[Void -> Void] = [{println("one")}, {println("two")}, {println("three")}]

First, I explained about using a generator and the next() function:

var myarray : [Void -> Void] = [{println("one")}, {println("two")}, {println("three")}]
var mygenerator = myarray.generate()

if let closure = mygenerator.next() {
closure()
}

if let closure = mygenerator.next() {
closure()
}

if let closure = mygenerator.next() {
closure()
}

That wasn’t practical for a generalized implementation.So I built a few loops that eventually ended up like this:

while true {
    if let closure = mygenerator.next() {
        closure()
    } else {
        break
    }
}

But Ken Ferry took one look at that, laughed, and suggested the following (far more elegant) solution instead:

while let closure = mygenerator.next() {closure()}

Beautiful and simple. Thanks, Ken.


Swift: Converting values to enumerations0 Comments

erica | 8:14 am | | Development,Swift

Yesterday in #swift-lang, an enumeration discussion buzzed. A chat participant asked, “Is there any way to go backwards in an enum? I want to look up an enum based on a value.” The answer is simple and accessible. Creating enumerations from values returned by services and function represents an important touchpoint in Swift development.

RawRepresentable

The RawRepresentable protocol consists of two underlying functions: toRaw() and fromRaw(). These enable you to transform enumerations to and from underlying data states.

protocol RawRepresentable {
    typealias Raw
    class func fromRaw(raw: Raw) -> Self?
    func toRaw() -> Raw
}

For example, if you base your enumeration on integers, you can use the underlying sequence to move to and from that representation.

enum Nums : Int { 
    case Zero
    case One
    case Two
    case Three
}

var z : Nums = Nums.fromRaw(2)!
z == .Two // true
z == .Three // false

This example uses an Int raw-value type for its underlying representation. The type appears just after the name of the enumeration.

Fun with Raw Values

The enumeration values do not have to exactly match 0, 1, 2, etc. For example, you might assign arbitrary values to the enumeration entries.

enum Nums : Int {
    case Zero = 5
    case One = 30
    case Two = 15
    case Three = 20
}

var z : Nums = Nums.fromRaw(20)!
z == .Two // false
z == .Three // true
println(Nums.Three.toRaw()) // prints 20

Nor are your raw-convertible enumerations limited to integers. You have access to any equatable literal, specifically integer literals, floating-point literals, string literals, booleans, and nil. For example, you might use strings as raw values:

enum Lets : String {
    case X = "x"
    case Y = "y"
    case Z = "z"
}

var zz = Lets.fromRaw("z")
zz! == .Z // true
println(Lets.Y.toRaw())

Each case must declare a unique name and value. If you skip the value for integers, as in the first example in this post, they implicitly inherit their order. The count starts at zero and increases monotonically from there.

Raw vs Associated Values

Don’t confuse raw values with associated values. A raw value is constant across all uses of an enumeration. They are defined in the enumeration declaration at compile time. Associated values enable you to store typed information in an enumeration. These are defined at runtime.

enum CocoaResult {
    case success(NSObject) // associated success value
    case failure(NSError) // associated error value
}

Swift: Capturing references in closures1 Comment

erica | 9:10 am | August 26, 2014 | Development,Swift

Consider the following code snippet. It creates a closure that prints out the value of the variable i. When it runs, should it print out 25, the value of the variable at the time the closure was created, or 35, the current contents of the memory pointed to by the variable reference?

var i = 25
var cl = {println(i)}
i = 35
cl()

If you paste this snippet into a playground, you’ll find that this code prints 35, and not 25. That’s because Swift closures default to capturing references, not values. To change this behavior and capture the value, use a capture list, as in the following example.

var i = 25
var cl = {[i] in println(i)}
i = 35
cl()

The use of [i] enables you to capture the value of i at the time you create the closure instead of at a later runtime.

Capture lists appear as the first item in a closure. They’re listed before any parameter clauses or identifier lists and require the in keyword to be used. For example, here’s another closure. This one is String -> Bool. It more or less does the same work as the previous closure but offers extra syntactic elements so you can see a capture list in a more complex setting.

var anotherClosure = {
    [i] (x : String) -> Bool in
    println(i)
    return true
}

Here’s another example, one that uses a class instance instead of an integer.

class MyClass {
var value = "InitialValue"
}

var instance = MyClass() // original assignment
var cl2 = {[instance] in println(instance.value)}
instance = MyClass() // updated assignment
instance.value = "UpdatedValue"
cl2()

If you omit the [instance] in capture list, this example prints out “UpdatedValue”, the value associated with the updated variable assignment. With the capture list, it prints “InitialValue”. This is the value stored by the original assignment.

When working with classes, a capture list can add modifiers to captured elements, specifically weak, unowned, unowned(safe) and unowned(unsafe). According to the reference material I’ve been reading, you most commonly see modifier usage when you want to capture self without reference cycles. The Swift Programming Language offers the following example. Here, the capture list enables you to capture the reference to self as an unowned — instead of strong — reference, avoiding reference cycles.

lazy var asHTML: () -> String = {
        [unowned self] in
        if let text = self.text {
            return "<\(self.name)>\(text)"
        } else {
            return "<\(self.name) />"
        }
    }

Thanks Kevin B.


iOS Utilities: UIImage from PDF0 Comments

erica | 3:34 pm | August 24, 2014 | Development,iOS

I’ve posted before about how the new PDF support in asset catalogs doesn’t really do what we expect (offer resizable vector assets). To make up for that, here’s a class that loads images from PDF files directly, building them to whatever UIImage size you need. Supply a path to the image and a target size, height, or width. If using a size, the functions will scale-aspect-fit to that target. With width or height, they’ll use the built-in aspect and build an appropriately sized partner dimension.

This class is part of my useful things repo, which is where I stash stuff that people may generally find useful. A bunch of classes and utilities are tied to my InformIT write-ups, but others meander there over time because I was inspired for whatever reason.

 


Swift: Calling Swift functions from Objective-C0 Comments

erica | 5:22 pm | August 21, 2014 | Development,Swift

It’s a lot easier than the docs make it out to be, especially if you’re just using a single target. Here’s my Swift file. Make sure you use the @objc keyword to tag your Swift classes so they’re available to your ObjC ones.

import Foundation

@objc class TestClass {
    class func `new`() -> TestClass {
        return TestClass()
    }
    
    func testFunction() {
        println("This function works")
    }
}

And here’s the Objective-C client:

#import "AppDelegate.h"
#import "TestProject-Swift.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application 
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    TestClass *instance = [TestClass new];
    [instance testFunction];
    return YES;
}
@end

The secret here is to import the name of the target in this case “TestProject” with the “-Swift.h” extension. Xcode builds this for you and hides it behind the scenes in the derived data. For the above example, mine was left at: DerivedData/TestProject-aqpeqeuqusyzdtcqddjdixoppyqn/Build/Intermediates/TestProject.build/Debug-iphoneos/TestProject.build/DerivedSources/TestProject-Swift.h

The .h file is actually quite interesting. Here is the interface that was built from my Swift code:

SWIFT_CLASS("_TtC11TestProject9TestClass")
@interface TestClass
+ (TestClass *)new;
- (void)testFunction;
- (instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end

There’s also a bit of fascinating cookiecutter set-up to be found in the header file. I encourage you to take a peek.


Swift: When Cocoa and Swift collide0 Comments

erica | 11:28 am | | Development,Swift

Consider the following code. Notice anything…unusual?

init(host: String) {
        self.host = host
        self.protectionSpace = NSURLProtectionSpace(host: self.host, port: 0, `protocol`: 
            "http", realm: nil, authenticationMethod: nil)
    }

Specifically, check out those back ticks used in-line as part of the method signature. They’re required here because the word protocol, in addition to being part of the method name, is a reserved word in Swift. The back ticks enable you to differentiate reserved words and identifiers.


Swift, Xcode: Beta 6 accessing Swift-native definitions1 Comment

erica | 10:02 am | August 20, 2014 | Development,Swift

Having any problems in Swift getting access to native definitions through Command-click? You’re not alone. (As one person put it, “b6 is [colloquial expression of extreme disappointment] even by Xcode beta standards”) Here’s a workaround.

Select any Foundation item like NSString and Command-click it like you used to. In the definitions file, use the Jump bar to move from Foundation > NSString > NSString to Swift.

Update: If Command-Click is not working within source code, try quitting/restarting Xcode (thanks Argyrios K.). Still borked for me in Playgrounds.

XcodeScreenSnapz001

 

This brings you to the Swift definitions you were trying to reach. Copy them to a file somewhere for easy reference.

Screen Shot 2014-08-20 at 9.59.45 AM

 


Swift, Xcode: There are many betas. I am number 6. You can call me “Caprica 6″2 Comments

erica | 12:18 pm | August 18, 2014 | Development,Swift,Xcode

Not a huge number of changes this week.

Having troubles opening Beta 6? Gus Mueller has an answer. Make sure to adjust the name of the app as needed, especially if you’ve renamed it as I have to keep your Keyboard Maestro macros running:

xattr -d com.apple.quarantine ./Xcode6-Beta.app

Goodbye .hasValue. I loved you  In Xcode 6 beta 6, (I’m sure there’s another 6 in there somewhere to make this the release of the beast) hasValue is gone. This makes me a little sad. Its semantic richness has been removed, a notes says “use != nil instead”. Syntactically fine, but the concept of “this container holds a payload” has gone away.

The positive test for optionalVariable.hasValue {…} will stick around, but a payload-check is now if optionalVariable == nil instead of if !optionalVariable.hasValue, which I found better told the story. The test against nil is handy and I don’t mind it but I don’t think it’s a superior option when evaluated against its brethren.

HomeKit accessory simulator Now you can pretend to turn lights off and on — even if you don’t own a fancy thermostat!

Foundation conformance updates. Remember all those T!’s I was recently complaining about, the ones that made no sense at all in Cocoa APIs? Many of them (officially a “large number”) have been audited for optional compliance.  That means Beta 5 calls like sendAsynchronousRequest(request: NSURLRequest!, queue: NSOperationQueue!, completionHandler handler: ((NSURLResponse!, NSData!, NSError!) -> Void)!) will now better match real world use.

In Beta 6, this call has been updated to sendAsynchronousRequest(request: NSURLRequest, queue: NSOperationQueue?, completionHandler handler: ((NSURLResponse!, NSData!, NSError!) -> Void)?), so the handler closure is still completely borked but at least the primary parameters are more thoughtfully assigned. At some point they really need to either introduce a Results enumeration (with value and error) or fix this to all optionals.

PRO TIP: When filing radars about API migration regarding implicitly unwrapped optionals, include #IUO in the subject line. Apple requests that you do not file radars about APIs that remain wrong, only those that were improperly converted away from IUOs. So I’m completely at a loss about what to do here. Apple writes, “Do not file feature requests about APIs that are still marked as T!, we know about them.” Well, okay then.

Bitwise operators are more NSFriendly. Apple writes “RawOptionSetType now implements to BitwiseOperationsType, so imported NS_OPTIONS now support the bitwise assignment operators |=, &=, and ^=”

Strings append but won’t concatenate. Remember the changes to Arrays back in Beta 5 — the ones where you could append two arrays but not add a new item? It now applies to Strings as well. You cannot add characters to strings — convert them to strings themselves and then add them.

Better voiding through science. C APIs that use void* will preserve the Void typealias.


Swift: What does 1.0 mean?4 Comments

erica | 1:41 pm | August 11, 2014 | Development,Swift

Been chatting about 1.0 — when it’s coming, what it will involve. The only thing that seems likely is that 1.0 will compile for 8.0, not that 1.0 will be code stable or act as a language development endpoint. Chris Lattner wrote, “Our goal for Swift 1.0 is for *apps* to be binary compatible with the OS, not for Swift 1.0 frameworks to be compatible with swift 2.0 frameworks.  The formal goal (what we’re shooting for) is relatively straight-forward, because apps are hemespherically sealed, and there is almost no dependence of swift 1.0 apps on the OS.”

I asked Kevin Ballard about when he saw Swift debuting. He told me, “I’m assuming 1.0 will be live when Xcode 6.0 is released, which I’m assuming has to be done for iOS 8. But that seems awfully soon for Swift, so maybe that won’t actually be the case. Or maybe they’ll do a 1.1 soon after to fix a lot of this stuff.” What everyone can agree on is that iOS 8′s timeline is way too early for Swift, and Apple reserves the right to continue to grow the language in a way that will keep breaking code.

It’s a very odd time to be a tech writer, with an interest in eventually writing about Swift (in my mind, my opus will be called A Swift Kick in the Ass. Dibs.) because to date Apple has continued to update its Swift Programming Language volume at each beta iteration. I assume this will continue as the language continues its evolution and development, which leaves the door open for getting-up-to-speed tutorials, best practices, and tips/tricks but excludes the standard-reference crowd who would be otherwise competing with the Word of Apple.  As a side note, readers expecting Apple-style auto-updating texts will be disappointed by the economics and realities of the tech writing world.

For now, it’s a swiftly moving target (pardon the pun — but yes, it was intentional) trying to keep up with where the language is and where it will be. It’s surprising how much keeps changing beta to beta, in terms of how much code even in a core set of routines needs to be re-written and re-thought through.

Over time playing with the language, what stands out the most though is how often the Swift language doesn’t really fit the Cocoa workflow with its requests, errors, and optional results. There are apparently bunches and bunches of radars for Result types filed with Apple. On the whole, the Cocoa libraries don’t take full advantage of Swift’s generics and enumerations, and other data types because they weren’t written to. Moving to Swift is like bending your head sideways through Rust and F# and all those other cool but psychedelic languages. It’s taking me time, but some of this stuff is starting to sink in and make me look at Swift as a destination of its own rather than just another way to get at the familiar APIs.

The machine-translated APIs don’t help reinforce confidence. They’re full of confusing choices and things that just seem wrong. I’ve started bypassing type inferencing when using Cocoa APIs. I document what I expect to receive, despite the visual redundancy. Upside, it’s giving some of the devs over in #swift-lang some good chuckles.

The more I use Swift, the more I think the Cocoa community should be looking at it as a long-range target. Sure, you’ll be able to develop and submit apps in it sometime soon, but it would probably be a really bad choice to do so for any team serious about maintainable, stable code for the next year at least.


« Older Posts

wordpress | sheepdip design by mahud © 2007