Slide 1

Slide 1 text

Realm Hands-on Osaka [email protected]

Slide 2

Slide 2 text

#realm_jp [email protected]

Slide 3

Slide 3 text

Katsumi Kishikawa Realm Inc. [email protected]

Slide 4

Slide 4 text

Realmͷμ΢ϯϩʔυ IUUQTSFBMNJPKQEPDTTXJGUMBUFTUTFDUJPO [email protected]

Slide 5

Slide 5 text

➙傈⡲׷،فٔ [email protected]

Slide 6

Slide 6 text

Slide 7

Slide 7 text

➙傈⡲׷،فٔ [email protected] HJUIVCDPNLJTIJLBXBLBUTVNJ3FBMN)BOET0O

Slide 8

Slide 8 text

أٓ؎س [email protected] CJUMZ3FBMN)BOET0O

Slide 9

Slide 9 text

Slide 10

Slide 10 text

Agenda ˖ 㛇劤箟 إحز،حف ؐؓ٦ىؚٝ،حف 5XJUUFSךة؎يٓ؎ٝ׾邌爙׃ג׫׷ 䒷׏䓸׏ג刿倜ָדֹ׷״ֲחׅ׷ 鼅䫛׃׋5XFFU׾-JLFדֹ׷״ֲחׅ׷ ˖ 䘔欽箟 5XFFU׾嗚稊דֹ׷״ֲחׅ׷ [email protected]

Slide 11

Slide 11 text

إحز،حف [email protected]

Slide 12

Slide 12 text

إحز،حف ˖ ؽٕس幥׫ؿٖ٦يٙ٦ؙ ˖ $PDPB1PET ˖ $BSUIBHF [email protected]

Slide 13

Slide 13 text

إحز،حف ˖ ؽٕس幥׫ؿٖ٦يٙ٦ؙ ˖ $PDPB1PET ˖ $BSUIBHF [email protected]

Slide 14

Slide 14 text

Slide 15

Slide 15 text

Slide 16

Slide 16 text

Slide 17

Slide 17 text

Slide 18

Slide 18 text

Slide 19

Slide 19 text

然钠ׅ׷ [email protected] import UIKit import RealmSwift @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { let realm = try! Realm() print(realm) return true } }

Slide 20

Slide 20 text

ؐؓ٦ي،حف [email protected]

Slide 21

Slide 21 text

ؐؓ٦ي،حف [email protected] import Foundation import RealmSwift class Tweet: Object { dynamic var name = "" dynamic var text = "" dynamic var iconURL = "" dynamic var id = "" dynamic var createdAt = NSDate() }

Slide 22

Slide 22 text

ؐؓ٦ي،حف [email protected] let tweet = Tweet() tweet.name = "test name" tweet.text = "test text" try! realm.write { realm.add(tweet) } let tweets = realm.objects(Tweet.self) for tweet in tweets { print(tweet.name) print(tweet.text) print(tweet.createdAt) }

Slide 23

Slide 23 text

5XJUUFSךة؎يٓ؎ٝ׾ 邌爙׃ג׫׷ [email protected]

Slide 24

Slide 24 text

Slide 25

Slide 25 text

ة؎يٓ؎ٝ׾邌爙 [email protected] import Foundation import RealmSwift class Tweet: Object { dynamic var name = "" dynamic var text = "" dynamic var iconURL = "" dynamic var id = "" dynamic var createdAt = NSDate() }

Slide 26

Slide 26 text

ة؎يٓ؎ٝ׾邌爙 [email protected] class Tweet: Object { dynamic var name = "" dynamic var text = "" dynamic var iconURL = "" dynamic var id = "" dynamic var createdAt = NSDate() static var dateFormatter: NSDateFormatter { let dateFormatter = NSDateFormatter() dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") dateFormatter.dateFormat = "EEE MMM dd HH:mm:ss Z yyyy" return dateFormatter } convenience init(tweetDictionary: [String: AnyObject]) { self.init() let user = tweetDictionary["user"] as! [String: AnyObject] name = user["name"] as! String text = tweetDictionary["text"] as! String iconURL = user["profile_image_url_https"] as! String id = tweetDictionary["id_str"] as! String createdAt = Tweet.dateFormatter.dateFromString(tweetDictionary["created_at"] as! String)! } }

Slide 27

Slide 27 text

ة؎يٓ؎ٝ׾邌爙 [email protected] import UIKit class TimelineCell: UITableViewCell { @IBOutlet weak var iconView: UIImageView! @IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var tweetTextView: UITextView! override func prepareForReuse() { iconView.image = nil nameLabel.text = nil tweetTextView.text = nil } }

Slide 28

Slide 28 text

Bة؎يٓ؎ٝ׾邌爙 [email protected] import UIKit import Accounts import Social import RealmSwift class TimelineViewController: UITableViewController { var account: ACAccount? func getHomeTimeline() { let requestURL = NSURL(string: "https://api.twitter.com/1/statuses/home_timeline.json") let request = SLRequest(forServiceType: SLServiceTypeTwitter, requestMethod: .GET, URL: requestURL, parameters: nil) request.account = account request.performRequestWithHandler { (data, response, error) -> Void in if let error = error { self.showAlert(error.localizedDescription) return } do { let results = try NSJSONSerialization.JSONObjectWithData(data, options: []) if let results = results as? NSDictionary { let errors = results["errors"] as! [[String: AnyObject]] let message = errors.last!["message"] as! String self.showAlert(message) return } let timeline = results as! [[String: AnyObject]] let realm = try! Realm() try! realm.write { timeline.forEach { (tweetDictionary) -> () in let tweet = Tweet(tweetDictionary: tweetDictionary) realm.add(tweet) } } } catch let error as NSError { self.showAlert(error.localizedDescription) } } } func showAlert(message: String) { dispatch_async(dispatch_get_main_queue()) { let alertController = UIAlertController(title: "Error", message: message, preferredStyle: .Alert) alertController.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil)) self.presentViewController(alertController, animated: true, completion: nil) } } }

Slide 29

Slide 29 text

Cة؎يٓ؎ٝ׾邌爙 [email protected] override func viewDidLoad() { super.viewDidLoad() let accountStore = ACAccountStore() let accountType = accountStore.accountTypeWithAccountTypeIdentifier(ACAccountTypeIdentifierTwitter) accountStore.requestAccessToAccountsWithType(accountType, options: nil) { (granted, error) -> Void in if granted { let accounts = accountStore.accountsWithAccountType(accountType) if let account = accounts.first as? ACAccount { self.account = account self.getHomeTimeline() } else { self.showAlert("No Twitter account") } } else { self.showAlert("No account access") } } }

Slide 30

Slide 30 text

Bة؎يٓ؎ٝ׾邌爙 [email protected] class TimelineViewController: UITableViewController { var timeline: Results? var notificationToken: NotificationToken? var account: ACAccount? ...

Slide 31

Slide 31 text

Cة؎يٓ؎ٝ׾邌爙 [email protected] override func viewDidLoad() { super.viewDidLoad() ... tableView.registerNib(UINib(nibName: "TimelineCell", bundle: nil), forCellReuseIdentifier: "timelineCell" tableView.rowHeight = 90 tableView.estimatedRowHeight = 90 let realm = try! Realm() timeline = realm.objects(Tweet).sorted("createdAt", ascending: false) notificationToken = timeline?.addNotificationBlock { [weak self] (change) in switch change { case .Initial(_): self?.tableView.reloadData() case .Update(_, deletions: _, insertions: _, modifications: _): self?.tableView.reloadData() case .Error(_): return } } }

Slide 32

Slide 32 text

ة؎يٓ؎ٝ׾邌爙 [email protected] override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return timeline?.count ?? 0 } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("timelineCell", forIndexPath: indexPath) as! TimelineCell let tweet = timeline![indexPath.row] cell.nameLabel.text = tweet.name cell.tweetTextView.text = tweet.text NSURLSession.sharedSession().dataTaskWithRequest(NSURLRequest(URL: NSURL(string: tweet.iconURL)!)) { (data, response, error) -> Void if let _ = error { return } dispatch_async(dispatch_get_main_queue()) { let image = UIImage(data: data!)! cell.iconView.image = image } }.resume() return cell } override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { return UITableViewAutomaticDimension }

Slide 33

Slide 33 text

ة؎يٓ؎ٝ׾邌爙 [email protected] import UIKit import Accounts import Social import RealmSwift class TimelineViewController: UITableViewController { var timeline: Results? var notificationToken: NotificationToken? var account: ACAccount? override func viewDidLoad() { super.viewDidLoad() let accountStore = ACAccountStore() let accountType = accountStore.accountTypeWithAccountTypeIdentifier(ACAccountTypeIdentifierTwitter) accountStore.requestAccessToAccountsWithType(accountType, options: nil) { (granted, error) -> Void in if granted { let accounts = accountStore.accountsWithAccountType(accountType) if let account = accounts.first as? ACAccount { self.account = account self.getHomeTimeline() } else { self.showAlert("No Twitter account") } } else { self.showAlert("No account access") } } tableView.registerNib(UINib(nibName: "TimelineCell", bundle: nil), forCellReuseIdentifier: "timelineCell") tableView.rowHeight = 90 tableView.estimatedRowHeight = 90 let realm = try! Realm() timeline = realm.objects(Tweet).sorted("createdAt", ascending: false) notificationToken = timeline?.addNotificationBlock { [weak self] (change) in switch change { case .Initial(_): self?.tableView.reloadData() case .Update(_, deletions: _, insertions: _, modifications: _): self?.tableView.reloadData() case .Error(_): return } } } func getHomeTimeline() { let requestURL = NSURL(string: "https://api.twitter.com/1/statuses/home_timeline.json") let request = SLRequest(forServiceType: SLServiceTypeTwitter, requestMethod: .GET, URL: requestURL, parameters: nil) request.account = account request.performRequestWithHandler { (data, response, error) -> Void in if let error = error { self.showAlert(error.localizedDescription) return } do { let results = try NSJSONSerialization.JSONObjectWithData(data, options: []) if let results = results as? NSDictionary { let errors = results["errors"] as! [[String: AnyObject]] let message = errors.last!["message"] as! String self.showAlert(message) return } let timeline = results as! [[String: AnyObject]] let realm = try! Realm() try! realm.write { timeline.forEach { (tweetDictionary) -> () in let tweet = Tweet(tweetDictionary: tweetDictionary) realm.add(tweet) } } } catch let error as NSError { self.showAlert(error.localizedDescription) } } } func showAlert(message: String) { dispatch_async(dispatch_get_main_queue()) { let alertController = UIAlertController(title: "Error", message: message, preferredStyle: .Alert) alertController.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil)) self.presentViewController(alertController, animated: true, completion: nil) } } override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return timeline?.count ?? 0 } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("timelineCell", forIndexPath: indexPath) as! TimelineCell let tweet = timeline![indexPath.row] cell.nameLabel.text = tweet.name cell.tweetTextView.text = tweet.text NSURLSession.sharedSession().dataTaskWithRequest(NSURLRequest(URL: NSURL(string: tweet.iconURL)!)) { (data, response, error) -> Void in if let _ = error { return } dispatch_async(dispatch_get_main_queue()) { let image = UIImage(data: data!)! cell.iconView.image = image } }.resume() return cell } override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { return UITableViewAutomaticDimension } }

Slide 34

Slide 34 text

չ䒷׏䓸׏ג刿倜պָ דֹ׷״ֲחׅ׷ [email protected]

Slide 35

Slide 35 text

Slide 36

Slide 36 text

B䒷׏䓸׏ג刿倜 [email protected]

Slide 37

Slide 37 text

C䒷׏䓸׏ג刿倜 [email protected] case .Error(_): return } } refreshControl?.addTarget(self, action: #selector(TimelineViewController.refresh(_:)), forControlEvents: .ValueChanged) } func refresh(sender: UIRefreshControl) { if let _ = self.account { getHomeTimeline() } } func getHomeTimeline() { let requestURL = NSURL(string: "https://api.twitter.com/1/statuses/home_timeline.json")

Slide 38

Slide 38 text

D䒷׏䓸׏ג刿倜 [email protected] func getHomeTimeline() { let requestURL = NSURL(string: "https://api.twitter.com/1/statuses/home_timeline.json") let request = SLRequest(forServiceType: SLServiceTypeTwitter, requestMethod: .GET, URL: requestURL, parameters: nil) request.account = account request.performRequestWithHandler { (data, response, error) -> Void in if let error = error { self.showAlert(error.localizedDescription) return } do { let results = try NSJSONSerialization.JSONObjectWithData(data, options: []) if let results = results as? NSDictionary { let errors = results["errors"] as! [[String: AnyObject]] let message = errors.last!["message"] as! String self.showAlert(message) return } let timeline = results as! [[String: AnyObject]] let realm = try! Realm() try! realm.write { timeline.forEach { (tweetDictionary) -> () in let tweet = Tweet(tweetDictionary: tweetDictionary) realm.add(tweet, update: true) } } } catch let error as NSError { self.showAlert(error.localizedDescription) } dispatch_async(dispatch_get_main_queue()) { self.refreshControl?.endRefreshing() }

Slide 39

Slide 39 text

䒷׏䓸׏ג刿倜 [email protected] import UIKit import Accounts import Social import RealmSwift class TimelineViewController: UITableViewController { var timeline: Results? var notificationToken: NotificationToken? var account: ACAccount? override func viewDidLoad() { super.viewDidLoad() let accountStore = ACAccountStore() let accountType = accountStore.accountTypeWithAccountTypeIdentifier(ACAccountTypeIdentifierTwitter) accountStore.requestAccessToAccountsWithType(accountType, options: nil) { (granted, error) -> Void in if granted { let accounts = accountStore.accountsWithAccountType(accountType) if let account = accounts.first as? ACAccount { self.account = account self.getHomeTimeline() } else { self.showAlert("No Twitter account") } } else { self.showAlert("No account access") } } tableView.registerNib(UINib(nibName: "TimelineCell", bundle: nil), forCellReuseIdentifier: "timelineCell") tableView.rowHeight = 90 tableView.estimatedRowHeight = 90 let realm = try! Realm() timeline = realm.objects(Tweet).sorted("createdAt", ascending: false) notificationToken = timeline?.addNotificationBlock { [weak self] (change) in switch change { case .Initial(_): self?.tableView.reloadData() case .Update(_, deletions: _, insertions: _, modifications: _): self?.tableView.reloadData() case .Error(_): return } } refreshControl?.addTarget(self, action: #selector(TimelineViewController.refresh(_:)), forControlEvents: .ValueChanged) } func refresh(sender: UIRefreshControl) { if let _ = self.account { getHomeTimeline() } } func getHomeTimeline() { let requestURL = NSURL(string: "https://api.twitter.com/1/statuses/home_timeline.json") let request = SLRequest(forServiceType: SLServiceTypeTwitter, requestMethod: .GET, URL: requestURL, parameters: nil) request.account = account request.performRequestWithHandler { (data, response, error) -> Void in if let error = error { self.showAlert(error.localizedDescription) return } do { let results = try NSJSONSerialization.JSONObjectWithData(data, options: []) if let results = results as? NSDictionary { let errors = results["errors"] as! [[String: AnyObject]] let message = errors.last!["message"] as! String self.showAlert(message) return } let timeline = results as! [[String: AnyObject]] let realm = try! Realm() try! realm.write { timeline.forEach { (tweetDictionary) -> () in let tweet = Tweet(tweetDictionary: tweetDictionary) realm.add(tweet) } } } catch let error as NSError { self.showAlert(error.localizedDescription) } dispatch_async(dispatch_get_main_queue()) { self.refreshControl?.endRefreshing() } } } func showAlert(message: String) { dispatch_async(dispatch_get_main_queue()) { let alertController = UIAlertController(title: "Error", message: message, preferredStyle: .Alert) alertController.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil)) self.presentViewController(alertController, animated: true, completion: nil) } } override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return timeline?.count ?? 0 } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("timelineCell", forIndexPath: indexPath) as! TimelineCell let tweet = timeline![indexPath.row] cell.nameLabel.text = tweet.name cell.tweetTextView.text = tweet.text NSURLSession.sharedSession().dataTaskWithRequest(NSURLRequest(URL: NSURL(string: tweet.iconURL)!)) { (data, response, error) -> Void in if let _ = error { return } dispatch_async(dispatch_get_main_queue()) { let image = UIImage(data: data!)! cell.iconView.image = image } }.resume() return cell } override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { return UITableViewAutomaticDimension } }

Slide 40

Slide 40 text

فٓ؎ؤؗ٦ד ꅾ醱׾《׶ꤐֻ [email protected]

Slide 41

Slide 41 text

Bفٓ؎ؤؗ٦ [email protected] class Tweet: Object { dynamic var name = "" dynamic var text = "" dynamic var iconURL = "" dynamic var id = "" dynamic var createdAt = NSDate() ... override class func primaryKey() -> String? { return "id" } }

Slide 42

Slide 42 text

Cفٓ؎ؤؗ٦ [email protected] let timeline = results as! [[String: AnyObject]] let realm = try! Realm() try! realm.write { timeline.forEach { (tweetDictionary) -> () in let tweet = Tweet(tweetDictionary: tweetDictionary) realm.add(tweet, update: true) } }

Slide 43

Slide 43 text

鼅䫛׃׋5XFFU׾ -JLFדֹ׷״ֲחׅ׷ [email protected]

Slide 44

Slide 44 text

Slide 45

Slide 45 text

-JLFׅ׷ [email protected] class Tweet: Object { ... dynamic var favorited = false convenience init(tweetDictionary: [String: AnyObject]) { ... favorited = tweetDictionary["favorited"] as! Bool } }

Slide 46

Slide 46 text

-JLFׅ׷ [email protected] func postFavorite(id: String) { let realm = try! Realm() guard let tweet = realm.objectForPrimaryKey(Tweet.self, key: id) else { return } let requestURL: NSURL if tweet.favorited { requestURL = NSURL(string: "https://api.twitter.com/1.1/favorites/destroy.json")! } else { requestURL = NSURL(string: "https://api.twitter.com/1.1/favorites/create.json")! } let request = SLRequest(forServiceType: SLServiceTypeTwitter, requestMethod: .POST, URL: requestURL, parameters: ["id": request.account = account request.performRequestWithHandler { (data, response, error) -> Void in if let error = error { self.showAlert(error.localizedDescription) return } let realm = try! Realm() if let tweet = realm.objectForPrimaryKey(Tweet.self, key: id) { try! realm.write { tweet.favorited = !tweet.favorited } } } }

Slide 47

Slide 47 text

-JLFׅ׷ [email protected] override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let tweet = timeline![indexPath.row] postFavorite(tweet.id) tableView.deselectRowAtIndexPath(indexPath, animated: true) }

Slide 48

Slide 48 text

-JLFׅ׷ [email protected] import UIKit import RealmSwift class FavoritesViewController: UITableViewController { var likes: Results? var notificationToken: NotificationToken? override func viewDidLoad() { super.viewDidLoad() tableView.registerNib(UINib(nibName: "TimelineCell", bundle: nil), forCellReuseIdentifier: "timelineCell") tableView.rowHeight = 90 tableView.estimatedRowHeight = 90 let realm = try! Realm() likes = realm.objects(Tweet).filter("favorited = %@", true).sorted("createdAt", ascending: false) notificationToken = likes?.addNotificationBlock { [weak self] (change) in switch change { case .Initial(_): self?.tableView.reloadData() case .Update(_, deletions: _, insertions: _, modifications: _): self?.tableView.reloadData() case .Error(_): return } } } // MARK: - Table view data source override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return likes?.count ?? 0 } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("timelineCell", forIndexPath: indexPath) as! TimelineCell let tweet = likes![indexPath.row] cell.nameLabel.text = tweet.name cell.tweetTextView.text = tweet.text NSURLSession.sharedSession().dataTaskWithRequest(NSURLRequest(URL: NSURL(string: tweet.iconURL)!)) { (data, response, error) -> Void in if let _ = error { return } dispatch_async(dispatch_get_main_queue()) { let image = UIImage(data: data!)! cell.iconView.image = image } }.resume() return cell } override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { return UITableViewAutomaticDimension } }

Slide 49

Slide 49 text

Where to find us • ! Realm Japan User Group: facebook.com/groups/realmjp • ! Twitter: twitter.com/realmJapan • GitHub: github.com/realm • ! StackOverflow: ja.stackoverflow.com/questions/tagged/realm • ! Email: [email protected] • ! Slack: slack.realm.io/ [email protected]

Slide 50

Slide 50 text

Realm Japan User Group Facebook [email protected]

Slide 51

Slide 51 text

Support Chat Slack [email protected]

Slide 52

Slide 52 text

Ξϯέʔτ bit.ly/RealmJP_Kansai [email protected]

Slide 53

Slide 53 text

Questions? Katsuma Kishikawa [email protected] www.realm.io/jp @k_katsumi