LoginSignup
14
14

More than 5 years have passed since last update.

Swift Tips

Last updated at Posted at 2015-12-12

SwiftのTipsを書きます。

追記
Tips その2にするつもりだったものを投稿しました。
Tipsっぽくなくなってしまったので当記事のタイトルからその1を外しました。
クロージャのメモリ管理について

enum

Associated values enum

例えば下記のようなC言語の構造体と同じ意味合いのデータ構造はSwiftだと型情報と値をまとめられます。

enum Type {
    UNDEFINED,
    BOOLEAN,
    NUMBER,
    STRING
}

struct Variant {
    Type   type;
    int    boolval;
    double floatval;
    char * stringval;
}
enum Variant {
    case Bool(Swift.Bool)
    case Number(Double)
    case String(Swift.String)
}

Result

よく使われるResult型はこれとジェネリクスを組合せて、成否とそれに紐づく任意の情報をまとめています。

enum Result<T, U:ErrorType> {
   case Success(T)
   case Failure(U)
}

参考:Result.swift - GitHub Alamofire

struct

組合せ可能なオプション(OptionSetType)

struct MyOption: OptionSetType {
    private(set) var rawValue: UInt
    init(rawValue: UInt) { self.rawValue = rawValue }

    static let OptionA = MyOption(rawValue: 1)
    static let OptionB = MyOption(rawValue: 2)
    static let OptionC = MyOption(rawValue: 4)
}

// OptionA と OptionC の組合せ
let opt: MyOption = [.OptionA, .OptionC]

typealias

別名をつける

例えば何かしらの処理の完了時に呼び出されるクロージャがある場合、typealias を使うと下記のように書けます。

typealias CompleteHandler = (String, NSError) -> Void

func hoge(completion: CompleteHandler) {
    // ...
}

func fuga(completion: CompleteHandler) {
    // ...
}

typealiasを使わないとこうなります。引数名で意味は通りますが、
後から"クロージャの第二引数をOptionalにしたい"と思った時に変更漏れを起こすかもしれません。

func hoge(completion: (String, NSError) -> Void) {
    // ...
}

func fuga(completion: (String, NSError) -> Void) {
    // ...
}

クロージャに限らず型に意味を持たせられる時は typealias で別名を与えましょう。

Associated Types

下記のプロトコルを見てください。
typealiasを定義していますがどの型にも紐づけられていません。

protocol Container {
    typealias ItemType
    mutating func append(item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
}

これを関連型(Associated Types)といい、プロトコルを実装するクラスで紐づけを行います。
この時、Genericを使うこともできます。もちろん使わなくてもいいです。
typealias ItemType はどこいったの?と思いますがItemTypeが使われていた箇所を
すべて型指定に変えることで省略可能です。

struct Stack<Element>: Container {
    // original Stack<Element> implementation
    var items = [Element]()
    mutating func push(item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
    // conformance to the Container protocol
    mutating func append(item: Element) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Element {
        return items[i]
    }
}

何が嬉しいのかですが、型の制約を作れます。

func allItemsMatch<
    C1: Container, C2: Container
    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
    (someContainer: C1, _ anotherContainer: C2) -> Bool {
    // 省略...
}

SequenceType プロトコルなどで使われているので知っておくと実装する時に捗ります。

参照:Associated Types ーThe Swift Programming Language

String

文字列を複数行に分けて書く

let text = "hoge\nfuga\nfoo\nbar"
let text = [
    "hoge",
    "fuga",
    "foo",
    "bar",
].joinWithSeparator("\n")

print

デバッグモードの時だけ出力する

func print(items: Any..., separator: String = " ", terminator: String = "\n") {
    #if DEBUG
        Swift.print(items[0], separator:separator, terminator: terminator)
    #endif
}

デバッグモードのみで有効になる DEBUG の定義が必要です。

終端文字の指定

引数 terminator: で指定します。

// 改行させない
print("HOGE", terminator: "")
14
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
14