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

Folderol and Yosemite1 Comment

erica | 10:04 am | October 20, 2014 | Admin,OS X,Various Frustrations

Screen Shot 2014-10-20 at 9.42.53 AM

A last second (very last second) Yosemite API change is fixed and a new version of Folderol is awaiting review at iTunes Connect. I apologize for the inconvenience. Email me if you need a beta version to hold you through until the fix is approved.


Size dumps2 Comments

erica | 2:44 pm | September 15, 2014 | Development,iOS,Xcode

Make of this what you will. I’ve interspersed updates into everything that follows.

When I ran my older apps, everything ran at 320×568 on the new devices. To get the following numbers, I created entirely new projects. (Saniul Ahmed tweeted me that you need to provide current launch images to get the new dimensions.) Lesson: Update your launch images or create new projects to take full advantage of the new dimensions.

From the docs: “The iPhone 6 Plus uses a new Retina HD display with a screen scale of 3.0. To provide the best possible experience on these devices, include new artwork designed for this screen scale. In Xcode 6, asset catalogs can include images at 1x, 2x, and 3x sizes; simply add the new image assets and iOS will choose the correct assets when running on an iPhone 6 Plus. The image loading behavior in iOS also recognizes an @3x suffix.” So the 6 Plus is 3x. Right. (Even though it’s reporting oddly  in the below info dump.)

Compare and contrast with the marketing text: “The size of the new, higher-resolution Retina HD displays on iPhone 6 and iPhone 6 Plus may be the first thing you notice.” (The same  HD mention is here as well.) But the 6 non-plus is reporting correctly for @2x ,not @3x, so I suspect the marketing text is wrong. (Thanks akempgen)

Lesson: The 6 plus uses a 3x scale. The 6 does not. Retina HD seems to mean something different between marketing text (high density) and developer docs (3x resolution).

More explanation about iPhone 6 screens from the guys at PaintCode. Read about it here. Lesson: This new stuff is strange.

With no further ado, here are my original tests.

Testing iPhone 6 plus
iPhone Simulator
iPhone OS
8.0
iPhone Simulator
<UIView: 0x7f854596f7a0; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x7f854596bd50>>
<UIWindow: 0x7f854596e1e0; frame = (0 0; 414 736); gestureRecognizers = <NSArray: 0x7f854596edd0>; layer = <UIWindowLayer: 0x7f854596c0d0>>

Testing iPhone 6
iPhone Simulator
iPhone OS
8.0
iPhone Simulator
<UIView: 0x7ffb11415b80; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7ffb11402be0>>
<UIWindow: 0x7ffb14113000; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x7ffb14113a20>; layer = <UIWindowLayer: 0x7ffb1410f410>>

Testing iPhone 5s
iPhone Simulator
iPhone OS
8.0
iPhone Simulator
<UIView: 0x7fcb21d13d90; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7fcb21d13090>>
<UIWindow: 0x7fcb21d10e70; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x7fcb21d11770>; layer = <UIWindowLayer: 0x7fcb21d0d140>>

Testing iPhone 5
iPhone Simulator
iPhone OS
8.0
iPhone Simulator
<UIView: 0x7a0d6a50; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7a0d6310>>
<UIWindow: 0x7a17a5c0; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x7a17ac00>; layer = <UIWindowLayer: 0x7a17a550>>

Testing iPhone 4s
iPhone Simulator
iPhone OS
8.0
iPhone Simulator
<UIView: 0x7ae9a000; frame = (0 0; 320 480); autoresize = W+H; layer = <CALayer: 0x7ae9c730>>
<UIWindow: 0x7ae9c600; frame = (0 0; 320 480); gestureRecognizers = <NSArray: 0x7ae9cb20>; layer = <UIWindowLayer: 0x7ae9c210>>

Anyway, this was what I tested out:
Screen Shot 2014-09-15 at 2.54.04 PM


Swift: Command-line basics2 Comments

erica | 1:55 pm | August 29, 2014 | Development,Swift

Just because someone wandered along today asking about input from stdin. No guarantees about edge conditions.

import Foundation
import Darwin

var myString : UnsafeMutablePointer<Int8> = UnsafeMutablePointer.alloc(100)
println("Enter your name")
fgets(myString, 100, stdin)
let myName = String.fromCString(myString)
println("Hi \(myName!)")

Auto Layout: iOS 83 Comments

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 solutions2 Comments

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 enumerations1 Comment

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-C1 Comment

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.


« Older Posts

wordpress | sheepdip design by mahud © 2007