LoginSignup
42
36

More than 5 years have passed since last update.

[Swift] 再入門したメモ

Last updated at Posted at 2015-07-16

Swiftが出た当初、色々記事やメモを書きましたが、しばらくたってだいぶ仕様が変化しているのと、単純に忘れてる部分があるので改めて再入門してみます。

ただ、アップデートが激しく、過去の記事を見るとすでに仕様が変わってるように見えるものもあるので調べるのが大変・・。
ドキュメント見てもそれっぽいの見つからなかったりするし( ;´Д`)


CoreData

CoreDataは色々ハマりそうなので個別にメモ。

変数宣言

変数を宣言する場合は以下のようにします。

class EntityAccount : NSManagedObject {
    @NSManaged var name: String?
    @NSManaged var address: String?
}

Class名の設定

Class名の設定

こんな感じでモジュール名.エンティティ名という形でClass名を設定してやる必要があります。
なおモジュール名はアプリのターゲット名を利用するようです。(上の例ではHoge

参考: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/WritingSwiftClassesWithObjective-CBehavior.html


ちょっとしたメモ

リソースからJSONファイルを読み出す

ローカルに保存したJSONファイルを読み込む方法です。

let path = NSBundle.mainBundle().pathForResource("hoge", ofType: "json")
let fileHandle = NSFileHandle(forReadingAtPath: path)

let data = fileHandle?.readDataToEndOfFile()

// SwiftJSONとか使ってる場合はそれ使う
let jsonString = NSString(data: data!, encoding: NSUTF8StringEncoding) as? String
let json = JSON.parse(jsonString)

// NSJSONSerializationを使う場合
// var json: NSDictionary? = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments, error: nil) as? NSDictionary

Objective-Cとの互換など

objc_setAssociatedObjectobjc_getAssociatedObjectを使う

Swiftでも上記ランタイム関数が使用できます。

<objc/runtime.h>import ObjectiveC

import ObjectiveC

を指定する。

サンプルコード

runtime
import UIKit
import ObjectiveC

class Hoge {
    init() {
        //
    }
}

var pointer = Selector("pointer")
var str = "test"
var hoge = Hoge()

objc_setAssociatedObject(hoge, &pointer, str, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))

var str2 = objc_getAssociatedObject(hoge, &pointer) as! String
print(str2) // => "test"

Closureを保持する

Swiftでは、objc_setAssociatedObjectの値の部分はAnyObject!になっているので、そのままではClosureを渡すことができません。

その場合はラッパークラスを作って対応すると持たせることができるようです。
こちらを参考にしました(How do I pass in a void block to objc_setAssociatedObject in swift | Stackoverflow

closure-associated
class AnyBlock {
    var closure: ((Int) -> ())?

    init(_ closure: ((Int) -> ())?) {
        self.closure = closure
    }
}

let block: (Int) -> () { (a: Int) in
    // do something.
}

objc_setAssociatedObject(alertView, &blockKey, AnyBlock(block), UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))

言語仕様的なの

subscript

hoge[0]とかhoge["name"]とか、ArrayやDictionaryで要素にアクセスするのに使われる書式を、自作のクラスでも使えるようにするものです。

百聞は一見にしかずということでサンプルコードを見てもらえると分かるかと思います。

class Test {
    private var name: String?
    init(name: String?) {
        self.name = name
    }

    subscript(key: String) -> String? {
        get {
            if key == "name" {
                return self.name
            }

            return ""
        }
        set(name) {
            if key == "name" {
                self.name = name
            }
        }
    }
}

// How to use
var test = Test(name: "edo")
test["name"] = "aaa"
print(test["name"])

ちなみに複数の値を受けることもできるようです。

// 中略
subscript(key: String, index: Int) -> String? {
    if key == "name" {
        if index == 0 {
            return "Wow"
        }

        return self.name
    }

    return ""
}
// 中略

// How to use
var test = Test(name: "edo")
print(test["name", 0]) // => Wow
print(test["name", 1]) // => edo

NSData <-> Stringの変換

String->NSData
var str = "Hoge"
let data = str.dataUsingEncoding(NSUTF8StringEncoding)
NSData->String
var str: String = NSString(data: data, encoding:NSUTF8StringEncoding)

Closureをtypealiasで定義する

ObjCではBlocksをtypedefで定義して使いやすくしていましたが、Swiftでも同じようなことをClosureとtypealiasを使って実現することができます。

typealias-closure
typealias closureType = (paramType) -> (returnType)

// 例
typealias anyBlock = (String, Int) -> (Int)

ちなみに戻り値がない場合は以下のように書く。

typealias-noreturn
typealias closureTyep = (Int) -> ()

// 例
var hoge: closureType = { (a: Int) in
    // do something.
}

as?as!

詳細はAppleのドキュメントを参考に。

基本的にはOptionalな扱いの延長です。
主な違いは Down Cast で使われる、ということです。

Down Castの成功が確実なら!、失敗するかもしれない場合はOptionalな状態で評価(as?)し、もし失敗した場合はnilが返ります。


Namespace風に分解する

Swiftはnamespaceがある、というのが発表当時の内容でした。
実際、Module単位でnamespaceが分かれていますが、ちょっとしたプロジェクトでそれをやるのは大変なので、extensionを使うことでそれっぽいものが作れるようです。

A.swift
class Namespace {
    class Hoge {
        func test() {
            print("hoge")
        }
    }
}
B.swift
extension Namespace {
    class Fuga {
        func test() {
            print("fuga")
        }
    }
}
C.swift
var hoge = Namespace.Hoge()
hoge.test() // => "hoge"

var fuga = Namespace.Fuga()
fuga.test() // => "fuga"

funcのアンダースコア(_)とシャープ(#)

アンダースコアはラベルを必要としないような場合に指定するもの。つまり無名ラベルと考えるといいかも。
→と思ったけど、funcについてはそもそも現状は明示的にラベル(外部引数名)を設定しないと一般的な言語のように関数呼び出せるっぽい。

シャープはラベルと引数名を同じにしたい場合に使う。
サンプルは以下。

// アンダースコアはいらないかも。
func add(a: Int, b: Int) -> Int {
    return a + b
}

// 呼び出し
print(add(1, 2)) // => 3
// #は外部・内部引数名を一緒にしたい場合に使う。
// イニシャライザではこれがデフォルト挙動っぽい?
func add2(#a: Int, #b: Int) -> Int {
    return a + b
}

// 呼び出し
print(add2(a: 1, b: 2)) // => 3

イニシャライザとfuncは異なる?

ちなみにイニシャライザについてはまた別ルールがありそう。
ドキュメントあたってもなんかそれらしい記述が見当たりません;
(Stackoverflowとか見てると過去にはそういう記述があったふうのものは見かけますが・・)

funcはデフォルトが_、イニシャライザはデフォルトが#になってるように見える。


The init! Failable Initializer

Initialization | Apple Developer

Failableと書かれているだけあって、fail、つまりnilを返すことができるイニシャライザ、ということのよう。(英語の解釈間違ってたら指摘ください)

なのでinit!init?として、それがnilを返す可能性があることを明示できる、というわけですね。
開発していると確かにnilくんの? こないの?
ってことがありますが、それを明示できるのは利点です。
(ただ、初見だと「ん?」ってなりますが)


細かいメモ

#pragma mark を使う

Swiftでは#pragma markがそのままでは使えません。
以下のようにします。

// MARK: hoge

// セパレータを入れたい場合

// MARK: - hoge

参考記事

42
36
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
42
36