Swift で Objective-C の @synchronized

環境: Swift version 1.1 (swift-600.0.56.1)

クリティカルセクションを作りたいとき、Objective-C の場合は

@synchronized(obj) {
    ...
}

となるところを Swift の場合は

objc_sync_enter(obj)
    ...
objc_sync_exit(obj)

とする。

exit 漏れが怖いのでラップする。

func sync(lock: AnyObject, proc: () -> ()) {
    objc_sync_enter(lock)
    proc()
    objc_sync_exit(lock)
}
sync(obj) {
    ...
}

iOS で半透明なモーダルビューを表示する

環境: Swift version 1.1 (swift-600.0.56.1)

自作 UIViewController をモーダルで表示する

//SomeViewController
view.backgroundColor = UIColor(white: 0.2, alpha: 0.2)
//呼び出し側
let controller = SomeViewController()
controller.modalPresentationStyle = .OverCurrentContext
controller.modalTransitionStyle = .CrossDissolve
presentViewController:actionSheetViewController(true, completion:nil)

UIActionSheet を使う

単にボタンを表示したいだけの場合、 iOS7 までは UIActionSheet、iOS8 では UIAlertController を使う。

iOS のバージョン毎に分岐するのは面倒なので CocoaPods で RMUniversalAlert を追加すると便利。

# Podfile
pod 'RMUniversalAlert'
RMUniversalAlert.showActionSheetInViewController(self,
    withTitle: "タイトル",
    message: "メッセージ",
    cancelButtonTitle: "キャンセル",
    destructiveButtonTitle: "削除",
    otherButtonTitles: ["編集", "履歴"],
    tapBlock: {
        index in
        switch index {
        case UIAlertControllerBlocksCancelButtonIndex:
            // "キャンセル" をタップした場合の動作
        case UIAlertControllerBlocksDestructiveButtonIndex:
            // "削除" をタップした場合の動作
        case UIAlertControllerBlocksFirstOtherButtonIndex:
            // "編集" をタップした場合の動作
        case UIAlertControllerBlocksFirstOtherButtonIndex + 1:
            // "履歴" をタップした場合の動作
        default:
            break
        }
        return
})

追記

最新版の RMUniversalAlert(0.6) の場合、インタフェースが上記のような記述から以下のように変更されている。

  • tapBlock に渡す関数の型が Int -> () から (RMUniversalAlert,Int) -> () に変更
    • これに伴って、UIAlertControllerBlocksCancelButtonIndex, UIAlertControllerBlocksCancelButtonIndex, UIAlertControllerBlocksDestructiveButtonIndex, UIAlertControllerBlocksFirstOtherButtonIndex のような定数が無くなり、これらの値は RMUniversalAlert#{cancelButtonIndex, destructiveButtonIndex, firstOtherButtonIndex} から取得するようになった
  • iPad 用に引数 popoverPresentationControllerBlock の追加

以下のように記述する。

RMUniversalAlert.showActionSheetInViewController(self,
    withTitle: "タイトル",
    message: "メッセージ",
    cancelButtonTitle: "キャンセル",
    destructiveButtonTitle: "削除",
    otherButtonTitles: ["編集", "履歴"],
    popoverPresentationControllerBlock:{
        $0.sourceView = popoverView /* どの UIView の上に ActionSheet を表示するか */
        $0.sourceRect = view.frame
    },
    tapBlock: {
        (alertView, index) in
        switch index {
        case alertView.cancelButtonIndex:
            // "キャンセル" をタップした場合の動作
        case alertView.destructiveButtonIndex:
            // "削除" をタップした場合の動作
        case alertView.firstOtherButtonIndex:
            // "編集" をタップした場合の動作
        case alertView.firstOtherButtonIndex + 1:
            // "履歴" をタップした場合の動作
        default:
            break
        }
        return
})

Xcode6 で SourceKitService Crashed が頻発する場合の対処

SourceKitService Crashed が頻発するとコーディングが阻害されるし、悪い場合は、シンタックスハイライトやコード補完が効かなくなる。

根本的な解決方法は分からない。

とりあえず DerivedData ディレクトリを削除して Xcode を再起動すると改善する。

Xcode 6.1.1 (6A2008a) で確認。

DerivedData ディレクトリは Preference の Location タブを開き、DerivedData ディレクトリの右矢印をクリックすると Finder で開ける。

削除した状態でビルドした時にエラーが出る場合は、一旦 Product > Clean する必要がある。

f:id:suer:20141227210830p:plain