Posted at

Swift で Model を書いてみた (observer編)

More than 5 years have passed since last update.

こちらのスライドでなるほどなるほどと思いつつ、なんとなく Swift で書いてみました

iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞い(http://www.slideshare.net/mokemokechicken/iosandroidmodel)

Xcode6-Beta3 を使ってます


コード抜粋


ModelLocator.swift

class ModelLocator : NSObject {

class var sharedInstance : ModelLocator {
struct Singleton {
static var instance = ModelLocator()
}
return Singleton.instance
}

var events = EventModel()

init() {
println("ModelLocator init!")
}

func getEvent() -> EventModel {
return events
}

func setEvent(array:EventModel) -> EventModel {
events = array
return events
}

}



EventModel.swift

class EventModel : NSObject {

var resources = [EventData]()
let atnd_url = "http://api.atnd.org/events/?keyword=swift&format=json"

func getResources() -> [EventData] {
return resources
}

func requestAtndApi(){
let manager = AFHTTPRequestOperationManager()
manager.GET(
self.atnd_url,
parameters: nil,
success: {
(operation: AFHTTPRequestOperation!, responseObject: AnyObject!) in
if let dict = responseObject as? NSDictionary{
if let events: NSArray = dict["events"] as? NSArray{
var tmp_objects = [EventData]()
for event in events{
tmp_objects += EventData(event: event as NSDictionary)
}
self.resources = tmp_objects
}
}
},
failure: {
(operation: AFHTTPRequestOperation!, error: NSError!) in
println(error.localizedDescription)
})
}
}



EventData.swift

class EventData : NSObject {

var title:String = ""
var url:String = ""

init(event:NSDictionary) {
super.init()
self.setModel(event)
}

func setModel(event:NSDictionary){
let title: AnyObject! = event["title"]
let url: AnyObject! = event["owner_twitter_img"]
self.title = title.description
self.url = url.description
}

}



HogeViewController.swift

ModelLocator.sharedInstance.getEvent().addObserver(self, forKeyPath: "resources", options: NSKeyValueObservingOptions(), context: nil)

ModelLocator.sharedInstance.getEvent().requestAtndApi()


HogeViewController.swift

...

override func observeValueForKeyPath(keyPath: String!, ofObject object: AnyObject!, change: [NSObject : AnyObject]!, context: UnsafePointer<()>) {
events = ModelLocator.sharedInstance.getEvent().getResources() as NSArray
self.tableView.reloadData()
}
...
override func viewDidDisappear(animated: Bool){
ModelLocator.sharedInstance.getEvent().removeObserver(self, forKeyPath: "resources")
}
...

ぺたぺた


気をつける事

最初、EventModel で以下のような初期化をして、通知を手動で行っていたのですが、

...

var resources = NSMutableArray()
...
self.willChangeValueForKey("resources")
resouces.addObject(model)
self.didChangeValueForKey("resources")
...

Swift っぽい以下の書き方に変更したら resources に += model する度に通知が行われてしまっていたので、一旦 tmp_objects に格納するように変更しました

var resources = [EventData]()

へー


参考

Swift でシングルトン(http://qiita.com/1024jp/items/3a7bc437af3e79f74505)

デザインパターンもっと読みたい読みたい

マイナビニュース デザインパターンをObjective-Cで(http://news.mynavi.jp/column/objc/)