Skip to content

Instantly share code, notes, and snippets.

@jacklynrose
Last active August 29, 2015 14:13
Show Gist options
  • Save jacklynrose/6383c5a726b388a69aad to your computer and use it in GitHub Desktop.
Save jacklynrose/6383c5a726b388a69aad to your computer and use it in GitHub Desktop.
Using self-invoking closures for tricky mutable dictionary values.

Swift Self-invoking Closures

While working on the iOS Development with Swift book I decided on this code for an example I'm using in the chapter that talks about composing views together. This is a silly little scroll view that displays a user's bio, and is actually used by a ProfileView that contains this and a UserDetailsView.

Profile View

Explaination

On line 19 I'm creating the setter for the text property that basically is meant to act as a way to apply default attributes to a plain string and assign it to the bio label's attributedText property.

I started making the NSAttributedString and was ready to have to do a bunch of build up crap to build the dictionary first and the paragraph style and such, and then I realised… SELF-INVOKING CLOSURES! I personally feel this is a bit more "Swift-y" and I was actually really impressed with the fact the type system didn't get in the way here, though that's just because of the context really (type is [AnyObject:AnyObject]).

Would love all your thoughts.

//
// UserBioView.swift
// Profile
//
// Created by Jack Watson-Hamblin on 18/01/2015.
// Copyright (c) 2015 ACME Inc. All rights reserved.
//
import UIKit
class UserBioView: UIScrollView {
let bio = UILabel(frame: CGRectZero)
var text: NSString {
get {
return bio.text!
}
set {
bio.attributedText = NSAttributedString(string: newValue, attributes: [
NSParagraphStyleAttributeName : ({
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineHeightMultiple = 1.5
return paragraphStyle
})()
])
}
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(bio)
bio.numberOfLines = 0
bio.font = UIFont(name: "Georgia", size: 14)
}
override func layoutSubviews() {
let bioSize = bio.sizeThatFits(frame.size)
bio.frame = CGRectMake(20, 20, bioSize.width - 40, bioSize.height - 40)
self.contentSize = CGSizeMake(bio.frame.size.width + 40, bio.frame.size.height + 60)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment