Learn Swift / viva Cocoa / viva Cocoa


Learn Swift / サンプルプログラム  Memo Pad 2


Model クラスのコード説明に注釈を追加しました。追加した注釈は緑字で記述しています。Feb. 19, 2016
Model クラスのコード説明と、エンコーダーとデコーダーの説明に間違いがあり訂正をしました。訂正箇所は赤字で記述しています。Feb. 14 2016

掲載開始日:2016年02月10日
最終更新日:2015年02月19日

home  目次  前へ  次へ  mail


Model クラスの作成

 ナビゲータエリアで「Memo Pad」フォルダを選択して、「File」メニュー →「New」→「File...」を選んでください。

 次のパネルで「OS X」の「Source」を選び、「Cocoa Class」を選んでください。そして「Next」をクリックします。

 次のパネルでは、Class: に「Model」と入力してください。Subclass of: は「NSObject」を選び、Language では「Swift」を選びます。設定が終わりましたら「Next」をクリックしてください。

 次のパネルでは、デフォルトのままで「Create」をクリックします。

 ナビゲータエリアに Model.swift が追加され、エディタエリアに Model.swift のコードが表示されます。


Model クラスのコーディング

 Model.swift に次のコードを記述してください。太字部分が追加するコードです。冒頭のコメント部分は省略しています。

import Cocoa

@objc(Model)
class Model: NSObject {
    var note:AnyObject = String()
    

}

@objc(Model)
Cocoa バインディングが、このクラスを見つけるためのコンパイラディレクティブです。自ら作成したクラスには、このコードを記述する必要があります。このコードを記述しないと、Cocoa バインディングが このクラスを見つけられなくなります。

class Model: NSObject {
Cocoa バイディングで使うクラスは、NSObject を継承している必要があります。

var note:AnyObject = String()
このコードは苦労しました。この一行を記述するために三日ほどかかりました。Swift を使った Cocoa バインディングでは、すべてデータは AnyObject 型でやり取りされます。したがって note プロパティの型は、AnyObject 型になります。そして、Swift のプロパティは必ず初期化されなければなりません。初期化するためには何らかのインスタンスが必要です。しかし AnyObject は単なる型であって、インスタンスを作成できるわけではありません。本来、この note プロパティに代入したいデータは、Text View が保持する NSTextStorage クラスのインスタンスです。ところが、Swift は、この NSTextStorage インスタンスを受け取ることが (理解することが )できません。代わりに Swift の String クラスを使ってみたところ、うまくいきました。Swift の String クラスは、Objcect-C の NSString の単なる互換クラスではなく、大きくパワーアップされているみたいです。

少し難しい話しになりますので、この注釈は読み飛ばしてもらっても構いません。var note:AnyObject = String() を、Objective-C で記述した場合は、次のようになります。
@property (readwrite, copy) NSTextStorage *note;
Objective-C の詳しいコード説明は割愛しますが、このコードには、copy というオプションが付いています。これは、Objective-C の配列の要素が参照型であるためです。一方、Swift の配列の要素は値型です。したがって、複製を作らなくても、各要素の値は違うものになります。


エンコーダーとデコーダー

 以上で、現段階で必要となるコーディングは完了しています。しかしながら、Model クラスの note プロパティのデータを、シリアライズ (serialize、バイト列化) したり、あるいは、シリアライズされたデータを元の形に復元するためには、エンコーダーとデコーダーと呼ばれるメソッドを記述しなければいけません。次のリストで太字部分がエンコーダーとデコーダーです。なお、このコードを今、記述する必要はありません。後ほど、ファイル入出力を説明する際に、再度説明いたします。今は眺めるだけで結構です。

import Cocoa

@objc(Model)
class Model: NSObject, NSCoding {
    var note:AnyObject = String()
    
    override init() {
        super.init()
    }
    
    required init?(coder aDecoder: NSCoder) {
        note = aDecoder.decodeObjectForKey("note")!
    }
    
    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeObject(note, forKey: "note")
    }
    
    
}
class Model: NSObject, NSCoding
Model クラスに、NSCoding プロトコルを採用しています。これにより、このクラスのプロパティを、シリアライズ (serialize、バイト列化) することができるようになります。なお、データをシリアライズ (バイト列化) することをエンコード (encode) といい、バイト列を元のデータに復元することをデコード (decode) と言います。 この Memo Pad では、note プロパティのデータをシリアライズしてからハードディスクに保存します。そのためにエンコーダーメソッドが必要が必要になります。またハードディスクからシリアライズされたデータを読み込みます。そのために、デコーダーメソッドが必要になります。

override init() { super.init() }
通常、すべてのプロパティに初期値がある場合は、init() メソッドを省略することができます。しかしここでは、NSCording で指定された init?() メソッドも記述しなければいけません。したがって、この init() メソッドを省略することはできません。

required init?(coder aDecoder: NSCoder) {
デコーダーメソッドです。2014年の Swift 登場以来、さまざまなデコーダーが使われてきたと思います。しかし、2016年2月現在、Xcode 7.2.1 でコンパイラを通るのは、このデコーダーメソッドだけではないかと思います。このメソッドは、Apple のクラスリファレンスに掲載されています。

note = aDecoder.decodeObjectForKey("note")!
デコーダーの実装です。行末に「!」をつけて、アンラップ (非オプショナル化) している以外は、変わったところはありません。

func encodeWithCoder(aCoder: NSCoder) {
エンコーダーです。特に変わったところはないと思います。

aCoder.encodeObject(note, forKey: "note")
エンコーダーの実装です。特に変わったところはないと思います。


お疲れ様でした。

 次のページでは、Memo Pad のコントローラを作成します。


home  目次  前へ  次へ  mail


無断転載禁止、リンクフリー
Copyright 2016. vivacocoa.jp All right reserved.