Slide 1

Slide 1 text

Realm Hands-on Osaka kk@realm.io

Slide 2

Slide 2 text

#realm_jp kk@realm.io

Slide 3

Slide 3 text

Katsumi Kishikawa Realm Inc. kk@realm.io

Slide 4

Slide 4 text

Realmͷμ΢ϯϩʔυ IUUQTSFBMNJPKQEPDTTXJGUMBUFTUTFDUJPO kk@realm.io

Slide 5

Slide 5 text

➙傈⡲׷،فٔ kk@realm.io

Slide 6

Slide 6 text

kk@realm.io

Slide 7

Slide 7 text

➙傈⡲׷،فٔ kk@realm.io HJUIVCDPNLJTIJLBXBLBUTVNJ3FBMN)BOET0O

Slide 8

Slide 8 text

أٓ؎س kk@realm.io CJUMZ3FBMN)BOET0O

Slide 9

Slide 9 text

"HFOEB kk@realm.io

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

إحز،حف kk@realm.io

Slide 12

Slide 12 text

إحز،حف ˖ ؽٕس幥׫ؿٖ٦يٙ٦ؙ ˖ $PDPB1PET ˖ $BSUIBHF kk@realm.io

Slide 13

Slide 13 text

إحز،حف ˖ ؽٕس幥׫ؿٖ٦يٙ٦ؙ ˖ $PDPB1PET ˖ $BSUIBHF kk@realm.io

Slide 14

Slide 14 text

kk@realm.io

Slide 15

Slide 15 text

kk@realm.io

Slide 16

Slide 16 text

kk@realm.io

Slide 17

Slide 17 text

kk@realm.io

Slide 18

Slide 18 text

kk@realm.io

Slide 19

Slide 19 text

然钠ׅ׷ kk@realm.io 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

ؐؓ٦ي،حف kk@realm.io

Slide 21

Slide 21 text

ؐؓ٦ي،حف kk@realm.io 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

ؐؓ٦ي،حف kk@realm.io 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ךة؎يٓ؎ٝ׾ 邌爙׃ג׫׷ kk@realm.io

Slide 24

Slide 24 text

kk@realm.io

Slide 25

Slide 25 text

ة؎يٓ؎ٝ׾邌爙 kk@realm.io 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

ة؎يٓ؎ٝ׾邌爙 kk@realm.io 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

ة؎يٓ؎ٝ׾邌爙 kk@realm.io 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ة؎يٓ؎ٝ׾邌爙 kk@realm.io 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ة؎يٓ؎ٝ׾邌爙 kk@realm.io 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ة؎يٓ؎ٝ׾邌爙 kk@realm.io class TimelineViewController: UITableViewController { var timeline: Results? var notificationToken: NotificationToken? var account: ACAccount? ...

Slide 31

Slide 31 text

Cة؎يٓ؎ٝ׾邌爙 kk@realm.io 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

ة؎يٓ؎ٝ׾邌爙 kk@realm.io 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

ة؎يٓ؎ٝ׾邌爙 kk@realm.io 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

չ䒷׏䓸׏ג刿倜պָ דֹ׷״ֲחׅ׷ kk@realm.io

Slide 35

Slide 35 text

kk@realm.io

Slide 36

Slide 36 text

B䒷׏䓸׏ג刿倜 kk@realm.io

Slide 37

Slide 37 text

C䒷׏䓸׏ג刿倜 kk@realm.io 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䒷׏䓸׏ג刿倜 kk@realm.io 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

䒷׏䓸׏ג刿倜 kk@realm.io 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

فٓ؎ؤؗ٦ד ꅾ醱׾《׶ꤐֻ kk@realm.io

Slide 41

Slide 41 text

Bفٓ؎ؤؗ٦ kk@realm.io 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فٓ؎ؤؗ٦ kk@realm.io 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דֹ׷״ֲחׅ׷ kk@realm.io

Slide 44

Slide 44 text

kk@realm.io

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

-JLFׅ׷ kk@realm.io 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ׅ׷ kk@realm.io 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ׅ׷ kk@realm.io 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: help@realm.io • ! Slack: slack.realm.io/ kk@realm.io

Slide 50

Slide 50 text

Realm Japan User Group Facebook kk@realm.io

Slide 51

Slide 51 text

Support Chat Slack kk@realm.io

Slide 52

Slide 52 text

Ξϯέʔτ bit.ly/RealmJP_Kansai kk@realm.io

Slide 53

Slide 53 text

Questions? Katsuma Kishikawa kk@realm.io www.realm.io/jp @k_katsumi