Swift(Appleプログラミング言語)の使い方リファレンス(サンプルコードあり)
という方針で執筆していきます。
下記の構成と項目keywordを考えて書いています。
プログラミング言語Swift日本語チュートリアルでは、手っ取り早くプログラミングに着手できるように、高度な項目を割愛し、学習項目を抑えた構成にしてあります。
- チュートリアル前編:http://xavier.hateblo.jp/entry/2014/06/12/223346
- チュートリアル後編:http://xavier.hateblo.jp/entry/2014/06/14/201418
丁寧な解説 or iPhone/iPadアプリ開発情報をお求めの方へ
既にSwiftの書籍が発行されているようですので、参考になさって下さい
- 作者: 諏訪悠紀,小室啓,掛川敦史
- 出版社/メーカー: 技術評論社
- 発売日: 2014/06/19
- メディア: Kindle版
- この商品を含むブログを見る
iPhone/iPadアプリ開発の説明は(今のところ)ありません。書籍等を参考になさって下さい
絶対に挫折しない iPhoneアプリ開発「超」入門【iOS7対応】増補改訂版
- 作者: 高橋京介
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2014/01/28
- メディア: 大型本
- この商品を含むブログを見る
iOSアプリ開発達人のレシピ100―開発現場で実証された実用コード集
- 作者: 堤修一
- 出版社/メーカー: 秀和システム
- 発売日: 2013/05/28
- メディア: 単行本
- この商品を含むブログ (1件) を見る
Appleプログラミング言語Swiftの使い方まとめ(日本語リファレンス)
タプル
タブルは、任意の型、任意の個数の値をまとめて、ひとつの値として扱えるようにしたもの
let player = (7, Position.Guard, "John") // enum Position { case Guard }みたいなものを仮定 let (number, position, name) = player let (_, pos, first_name) = player let player_name = player.2 let player2 = (number: 7, position: Position.Guard, name: "John") let player_name2 = player2.name
- 変数に、タプルを分解して代入すれば、普通の変数同様に使える
- 分解して代入するときに不要な要素は、下線で受け取れば、その値は無視される
- 要素にはインデックス(ゼロ始まり)でアクセスすることも出来る
- タプル内で要素名を与えておくと、値を参照するときに使える
表明(アサーション、アサート、Assertion)
アサーションを使って、処理が先に進む前に、必要な条件が成り立っていることをチェックします。
例えば、配列の添字が要素数に納まっていること、外部から受け取った文字列が危険でないことなど。
assert(value_to_be_negative < 0) assert(value_to_be_negative < 0, "value_to_be_negative actually is not negative") // assert(value_to_be_negative < 0, "value_to_be_negative: " + String(value_to_be_negative)) // => エラー // assert(value_to_be_negative < 0, "value_to_be_negative: \(value_to_be_negative)") // => エラー
型キャスト
型キャストは、あるインスタンスの型を別の型としてチェックしたり、別の型として扱ったりする仕組み
Swiftでは、ある型がプロトコルに従っているかをチェックしたり、そのプロトコルとして扱ったりするためにも使われる。
class MoviePlayer { } class BlueRay : MoviePlayer { func seek() {/* */} } class Beta : MoviePlayer { func rewind() {/* */} } func start(mp : MoviePlayer) { if mp is Beta { let beta = mp as Beta beta.rewind() } (mp as Beta).rewind() // 乱暴 (mp as? Beta)?.rewind() if let beta as? Beta { beta.rewind() } }
拡張(Extension)
既存のクラスに対して、定義されているソースコードを使わずに、機能追加する仕組み
extension OriginalTypeA { /* OriginalTypeAに追加したい内容を書く */ } extension OriginalTypeB: ProtocolX, ProtocolY { /* ProtocolXとProtocolYに従った内容を書く */ } extension String { var hiraganaYomi : String { var yomi = "" // 略 かっこいいアルゴリズム考えて下さい m(_ _)m return yomi } } extension Int { func upto(max: Int, proc: (n: Int) -> ()) { proc(n) } mutating func negate() { self = self < 0 ? self : -self } subscript(n: UInt) -> Int { // n桁めの数字を取り出す var x = 1 for _ in 1..n { x *= 10 } return (self / x) % 10 } enum Unit { case K = 1024 case M = 1048576 } func inUnit(unit : Unit) -> Double { return self / unit.toRaw } } 3.upto(6) { println($0) } 1234[1]
- 拡張を定義するには、extensionを使う
- 計算されるプロパティーを追加することが出来る
- 値を保持するプロパティーを追加することは出来ない
- 既存のプロパティーのobserverを追加することは出来ない
- クラスメソッド、インスタンスメソッドを追加できる
- selfやプロパティーを変更するメソッドにはmutatingを付けなければいけない
- 入れ子にした型を追加できる
- 添字演算子を追加することが出来る
- (designated initializer*1以外の)initializerを追加することが出来る
- designated initializerはオリジナルのクラスで定義されていなければいけない
- 全てのプロパティーにデフォルト値がありかつinitを定義していない構造体や列挙を拡張する場合は、拡張のイニシャライザーの中から、デフォルトイニシャライザーを呼んだのち、各メンバーのイニシャライザーを呼ぶことが出来る
プロトコル
プロトコルとは、ひとまとまりの機能を提供するために必要なプロパティーやメソッドのひな形
protocol ProtocolX { var readOnly: Int { get } var readWrite: Int { get set } class var typeProperty: Int { get set } } class ClassXYZ: ClassZ, ProtocolX, ProtocolY { /* ここに定義 */ }
- プロトコルを定義するには、protocolを使う
- 型の定義でプロトコルに従っていることを示すには、型名の後ろに、コロンに続けて、カンマ区切りでプロトコルを記述する
- コロンの後ろに親クラスも指定したい場合、親クラスを最初に書く
- プロトコルは型の一種なので、
- 変数、定数、プロパティー、関数のパラメーター/戻り値、コンテナ要素の型指定に使える
- プロトコル名は大文字で始めるようにする(小文字も一応可能)
- varでプロパティーの指定ができる:
- 名前、型、readオンリーかread/write可能かどちらかの3項目を指定しなければいけない
- readオンリーであることは{ get }で指定する
- read/write可能であることは{ get set }で指定する
- 計算される/されないとか値を保持する/しないは指定できない
- 型プロパティーである場合は、最初にclassを付ける
protocol ProtocolY { func a() -> Int class func b() -> Int } class Y : ProtocolY { func a() -> Int { /* 何らかの実装 */ } class func b() -> Int { /* 何らかの実装 */ } } protocol ProtocolX { mutating func c() -> Int } struct X { mutating func c() -> Int { /* 何らかの実装 */ } }
- インスタンスメソッドと型メソッドを指定できる
- メソッド定義から本体(つまり{})を除いた形式で指定する
- デフォルト引数の指定は出来ない
- 型メソッドを定義するには、先頭にclassを付ける
- 構造体や列挙を定義するときにstaticで実装されるにしても、classを付ける(?)
- メソッドにインスタンスを変更することを許可するには、funcの前にmutatingを付ける
- 構造体や列挙の定義でmutatingメソッドを実装する場合、funcの前にmutatingを付ける必要がある
- クラス定義の中では不要(mutatingを付けるとエラーになる)
- 構造体や列挙の定義でmutatingメソッドを実装する場合、funcの前にmutatingを付ける必要がある
@objc protocol Messenger { func sendMessage() @optional func compressMessage() -> String } class QuickMessenger : Messenger { func sendMessage() { /* 何らかの実装 */ } func compressMessage() -> String { /* 何らかの実装 */ } } class RapidMessenger : Messenger { func sendMessage() { /* 何らかの実装 */ } } let qm = QuickMessenger() let message0 : String = qm.compressMessage() var m = qm as Messenger let message1 : String? = m.compressMessage?() let rm = RapidMessenger() m = rm as Messenger let message2 : String? = m.compressMessage?() // => nill
- プロトコルの条件の中で、実装側に必ずしも必要ではないものには、@optionalを付けておく
- オプショナルなプロパティー/メソッドの値はオプショナル値になる
- メソッド定義が普通の(オプショナルでない)型を返しても、呼び出した結果はオプショナル値
class Employee {} @objc protocol HighSpec { func workHard() } class SoldierEmployee : Employee, HighSpec { func workHard() { /* 程々に定義してあげて下さい m(_ _)m */ } } func runBusiness(employees: Employee[]) { for employee in employees { if employee is HighSpec { let excellentEmployee = employee as HighSpec excellentEmployee.workHard() } if let workaholic = employee as? HighSpec { workaholic.workHard() } (employee as HighSpec).workHard() // これはあかん。使い方がひどいわ。社員は悪くないんや。 } } @objc protocol Executive { func leadMembers() func readNumbers() } @objc protocol Creative { func createProducts() } class TopEngineer : Employee { // クラス定義にはプロトコル指定なし func createProducts() { /* 略 */ } func operateServices() { /* 略 */ } func leadMembers() { /* 略 */ } func readNumbers() { /* 略 */ } } func isCreativeOrExecutive(employee : Employee) -> Bool { return employee is Creative || employee is Executive } let topEngineer = TopEngineer() isCreativeOrExecutive(topEngineer) // => false // こいつらできるやないかと気づいたら、 extension TopEngineer : Executive, Creative {} // 後からでもこうしてあげればえぇんやで〜 isCreativeOrExecutive(topEngineer) // true func assignToImportantProject(superEmployee: protocol<Executive, Creative>) { superEmployee.leadMembers() superEmployee.createProducts() } assignToImportantProject(topEngineer)
- isで、クラスインスタンスがプロトコルに従っていることを確認できる
- asで、そのプロトコル型のオブジェクトにキャストする
- キャストが失敗したら実行時エラーに成る
- as?で、インスタンスがプロトコルに従っていることを確認しつつそのプロトコル型としてキャストすることができる
- 型があるプロトコルの要件を満たしているだけでは、そのプロトコルに従っている型として認められない
- あるプロトコルの要件を既に満たしている型をそのプロトコルと結びつけるためには、空のextensionを書く
- プロトコルは継承することによって、要件を追加することが出来る
- 型の指定として複数のプロトコルを組み合わせることができる(プロトコル合成:protocol compositionという)
型エイリアス
型に別名を付けることが出来る
typealias UserId = UInt var userId : UserId = 3 UserId.min // => UInt = 0 String(userId) // => String = "3"
- typealiasを使う
- 元の型に対して出来ることが、全てそのまま出来る
*1:そのクラスで定義された全てのプロパティーの値を指定できるinit