Swiftが出た当初、色々記事やメモを書きましたが、しばらくたってだいぶ仕様が変化しているのと、単純に忘れてる部分があるので改めて再入門してみます。
ただ、アップデートが激しく、過去の記事を見るとすでに仕様が変わってるように見えるものもあるので調べるのが大変・・。
ドキュメント見てもそれっぽいの見つからなかったりするし( ;´Д`)
CoreData
CoreDataは色々ハマりそうなので個別にメモ。
変数宣言
変数を宣言する場合は以下のようにします。
class EntityAccount : NSManagedObject {
@NSManaged var name: String?
@NSManaged var address: String?
}
Class名の設定
こんな感じでモジュール名.エンティティ名
という形でClass名を設定してやる必要があります。
なおモジュール名はアプリのターゲット名を利用するようです。(上の例ではHoge
)
ちょっとしたメモ
リソースから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_setAssociatedObject
、objc_getAssociatedObject
を使う
Swiftでも上記ランタイム関数が使用できます。
<objc/runtime.h>
はimport ObjectiveC
import ObjectiveC
を指定する。
サンプルコード
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)
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の変換
var str = "Hoge"
let data = str.dataUsingEncoding(NSUTF8StringEncoding)
var str: String = NSString(data: data, encoding:NSUTF8StringEncoding)
Closureをtypealiasで定義する
ObjCではBlocksをtypedef
で定義して使いやすくしていましたが、Swiftでも同じようなことをClosureとtypealias
を使って実現することができます。
typealias closureType = (paramType) -> (returnType)
// 例
typealias anyBlock = (String, Int) -> (Int)
ちなみに戻り値がない場合は以下のように書く。
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
を使うことでそれっぽいものが作れるようです。
class Namespace {
class Hoge {
func test() {
print("hoge")
}
}
}
extension Namespace {
class Fuga {
func test() {
print("fuga")
}
}
}
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