viva CocoaさんのコードサンプルMemo Padにおけるアップデート内容

主題
viva CocoaさんのXcodeとSwiftで作るMac OS Xアプリ開発のサンプルプログラムMemo Padにおけるコードサンプルについて、アップデートした内容を説明する。

背景
今まで3個のmacOS用アプリを公開してきた。しかしながら、その多くにおいて取ってきた手法は、Web上に公開されているサンプルコードを組み合わせるというものだった。この辺りで軌道修正したいと思いつつも、新しいアプリでもサンプルコードを求める癖は抜けなかった。
そこで見つけたのがviva CocoaさんのXcodeとSwiftで作るMac OS Xアプリ開発の最終章にあるMemo Padであった。そこから逆にリンクを辿ってたどり着いたコンテンツはかなり体系的に整理されているようだった。これはうってつけだと思い、第1章から勉強し直すことにした。だが考え方は今でも全く問題なく通じるものの、掲載のコードサンプルにdeprecateされた内容などがあり、アップデートが必要なことが分かった。

  1. AddOneクラスコードサンプル
    変更点は、コメントにて説明している。

    import Cocoa
    
    @objc(AddOne)
    class AddOne: ValueTransformer {
    
        /* 元のコード
        override func transformedValue(value: AnyObject?) -> AnyObject? {
            var num = value!.intValue
            num! += 1
            return NSNumber.init(int: num)
        }
        */
    
        // 関数の形が変わった
        // override func transformedValue(value: AnyObject?) -> AnyObject?
        override func transformedValue(_ value: Any?) -> Any? {
    
            // 後でpowの結果と比較するため、倍精度型で定義
            var num:Double = 0.0
    
            // valueのnilチェック
            if let theValue = value {
                num = (theValue as AnyObject).doubleValue
            } else { return num = 0 }
    
            /*
               最初の9223372036854775807=(pow(2,63) - 1)を防ぐ。
               numを倍精度型にする理由は、ここでの比較のため。
              また92233…はpowでしか作れない(StackOverFlowにあった
              整数型powではEXC_BAD_INSTRUCTIONで落ちる)ため
            */
            if num < (pow(2,63) - 1) {
                num += 1
            } else {
                num = 0
            }
    
            return NSNumber.init(value: num)
        }
    }
  2. Modelクラスコードサンプル
    変更点は、コメントにて説明している。

    import Cocoa
    
    @objc(Model)
    
    // class Model: NSObject, NSCodingから変更
    class Model: NSObject, NSSecureCoding {
        // NSSecureCodingにより追加
        static var supportsSecureCoding: Bool = true
    
        // Cocoa-Bindingsでは、init()は、この形。それ以外はダメ
        override init() {
            super.init()
        }
    
        // @objcコンパイラディレクティブは必要。ないと落ちる。
        @objc var note: AnyObject = String() as AnyObject
    
        // encodeWithCoder(aCoder: NSCoder)から
        // encode(with aCoder: NSCoder)に変更
        func encode(with aCoder: NSCoder) {
            aCoder.encode(note, forKey: "note")
        }
    
        // decodeObjectForKey("note")!から
        // decodeObject(forKey: "note")!に変更
        required init?(coder aDecoder: NSCoder) {
            note = aDecoder.decodeObject(forKey: "note")! as AnyObject
       }
    }
  3. ViewControllerクラスコードサンプル
    変更点は、コメントにて説明している。

    import Cocoa
    
    class ViewController: NSViewController {
    
        // @objcコンパイラディレクティブは必要。ないと落ちる。
        @objc dynamic var notes:[AnyObject] = []
        // deprecateに伴い廃止。
        // var filePath:String = String()
    
        func save() {
            // archiveRootObject(_:toFile:)
            // はmacOS10.14でdeprecatedされた。
            guard let archiveData = try?
                NSKeyedArchiver.archivedData(withRootObject: notes,  requiringSecureCoding: true ) else {
                    fatalError("Archive failed")
            }
            UserDefaults.standard.set(archiveData, forKey: "notes")
        }
    
        func read() {
            // unarchiveObject(with:)
            // はmacOS10.14でdeprecatedされた。
            if let loadedData = UserDefaults().data(forKey: "notes") {
                if let file = try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(loadedData) {
                    notes = file as! [AnyObject]
                }
            }
        }
    
        override func viewWillAppear() {
            super.viewWillAppear()
    
            read()
            /* deprecateに伴い廃止。
            filePath = NSHomeDirectory() + "/Library/Application Support/viva Cocoa"
            do {
                try NSFileManager.defaultManager().createDirectoryAtPath(
                    filePath,
                    withIntermediateDirectories: true,
                    attributes: nil)
            } catch {
                print("Error")
            }
            filePath += "/Memo Pad.data"
            */
        }
    
        override func viewWillDisappear() {
            super.viewWillDisappear()
    
            save()
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // Do any additional setup after loading the view.
        }
    
        override var representedObject: Any? {
            didSet {
            // Update the view, if already loaded.
            }
        }
    
    
    }

以上。

この投稿へのコメント

コメントはありません。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

この投稿へのトラックバック

トラックバックはありません。

トラックバック URL