Slide 1

Slide 1 text

Realm meetup #18 [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

Recent Updates [email protected]

Slide 5

Slide 5 text

Recent Updates • Realm Objective-C/Swift 1.0.2 • Realm Java 1.1.1 (was 1.1.0) • Realm React Native 0.14.0 • Realm Xamarin 0.77.2 (was 0.76.0) [email protected]

Slide 6

Slide 6 text

Realm Objective-C/Swift 1.0.2 [email protected]

Slide 7

Slide 7 text

Realm Objective-C/Swift 1.0.2 • ϓϩύςΟ͕ଘࡏ͠ͳ͍ΫϥεΛอଘ͠Α͏ͱ͢Δͱྫ֎ʹ • write(_:)ϝιουͷϒϩοΫ಺ͰthrowͰ͖ΔΑ͏ʹ • όΠφϦαΠζ͕গ͠ݮগ • addNotificationBlock(_:, change:)Ͱॳճͷݺͼग़͠͸ඞ ͣ.Initial͕ݺ͹ΕΔΑ͏ʹ • ٯํ޲ͷؔ࿈͕มߋʹͳΔ৔߹ʹ௨஌͕ݺ͹Εͳ͍໰୊Λमਖ਼ [email protected] [email protected]

Slide 8

Slide 8 text

Already compatible with Swift 3 & Xcode 8 https://github.com/realm/realm-cocoa/issues/3796 [email protected]

Slide 9

Slide 9 text

Installing RealmSwift for Xcode 8 beta5 w/ Carthage [email protected] github "realm/realm-cocoa" "master"

Slide 10

Slide 10 text

Installing RealmSwift for Xcode 8 beta5 w/ Carthage [email protected] $ echo SWIFT_VERSION=\"3.0\">swift3.xcconfig $ XCODE_XCCONFIG_FILE=`pwd`/swift3.xcconfig \ carthage update --no-use-binaries

Slide 11

Slide 11 text

Installing RealmSwift for Xcode 8 beta5 w/ CocoaPods [email protected] platform :ios, '8.0' target '...' do use_frameworks! pod 'Realm', git: 'https://github.com/realm/realm-cocoa.git', branch: 'master', submodules: true pod 'RealmSwift', git: 'https://github.com/realm/realm-cocoa.git', branch: 'master', submodules: true post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '3.0' end end end end

Slide 12

Slide 12 text

Installing RealmSwift for Xcode 8 beta5 w/ CocoaPods [email protected] platform :ios, '8.0' target '...' do use_frameworks! pod 'Realm', git: '...', branch: 'master', submodules: true pod 'RealmSwift', git: '...', branch: 'master', submodules: true post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '3.0' end end end end

Slide 13

Slide 13 text

Installing RealmSwift for Xcode 8 beta5 w/ CocoaPods [email protected] platform :ios, '8.0' target '...' do use_frameworks! pod 'Realm', git: '...', branch: 'master', submodules: true pod 'RealmSwift', git: '...', branch: 'master', submodules: true post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '3.0' end end end end

Slide 14

Slide 14 text

Realm Xamarin 0.77.2 (was 0.76.0) [email protected]

Slide 15

Slide 15 text

Realm Xamarin 0.77.2 • εΩʔϚ৘ใΛࢀর͢ΔAPIͷ௥Ճ • Dynamic APIͷ௥Ճ • realm.CreateObject("ClassName"); • realm.All("ClassName") • RealmList => IList [email protected]

Slide 16

Slide 16 text

Best Practice & Tips [email protected]

Slide 17

Slide 17 text

Multi thread [email protected]

Slide 18

Slide 18 text

Multi thread [email protected] func updateUnread(id: String) { let realm = try! Realm() guard let tweet = realm.objectForPrimaryKey(Article.self, key: id) else { return } request.performRequestWithHandler { (data, response, error) in if let error = error { return } ... try! realm.write { tweet.unread = false } } }

Slide 19

Slide 19 text

Multi thread [email protected] func updateUnread(id: String) { let realm = try! Realm() guard let tweet = realm.objectForPrimaryKey(Article.self, key: id) else { return } request.performRequestWithHandler { (data, response, error) in if let error = error { return } ... try! realm.write { tweet.unread = false } } } !

Slide 20

Slide 20 text

Basic solution [email protected] func updateUnread(id: String) { let realm = try! Realm() guard let tweet = realm.objectForPrimaryKey(Article.self, key: id) else { return } request.performRequestWithHandler { (data, response, error) -> Void in if let error = error { return } let realm = try! Realm() if let tweet = realm.objectForPrimaryKey(Tweet.self, key: id) { try! realm.write { tweet.favorited = !tweet.favorited } } } }

Slide 21

Slide 21 text

Basic solution [email protected] func updateUnread(id: String) { let realm = try! Realm() guard let tweet = realm.objectForPrimaryKey(Article.self, key: id) else { return } request.performRequestWithHandler { (data, response, error) -> Void in if let error = error { return } let realm = try! Realm() if let tweet = realm.objectForPrimaryKey(Tweet.self, key: id) { try! realm.write { tweet.favorited = !tweet.favorited } } } }

Slide 22

Slide 22 text

Best practice [email protected] var timeline: Results? var notificationToken: NotificationToken? override func viewDidLoad() { super.viewDidLoad() ... let realm = try! Realm() timeline = realm.objects(Article.self) .sorted("creationDate", ascending: false) notificationToken = timeline?.addNotificationBlock { [weak self] (results, error) in if let _ = error { return } self?.tableView.reloadData() } } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return timeline?.count ?? 0 } func getTimeline() { ... request.performRequestWithHandler { (data, response, error) -> Void in if let error = error { self.showAlert(error.localizedDescription) return } let articles = try NSJSONSerialization.JSONObjectWithData(data, options: []) let realm = try! Realm() try! realm.write { articles.forEach { (article) -> () in ... realm.add(article, update: true) } } } }

Slide 23

Slide 23 text

Best practice [email protected] var timeline: Results? var notificationToken: NotificationToken? override func viewDidLoad() { super.viewDidLoad() ... let realm = try! Realm() timeline = realm.objects(Article.self) .sorted("creationDate", ascending: false) notificationToken = timeline?.addNotificationBlock { [weak self] (results, error) in if let _ = error { return } self?.tableView.reloadData() } }

Slide 24

Slide 24 text

Best practice [email protected] func getTimeline() { ... request.performRequestWithHandler { (data, response, error) -> Void in if let error = error { self.showAlert(error.localizedDescription) return } let articles = try NSJSONSerialization.JSONObjectWithData(data, options: []) let realm = try! Realm() try! realm.write { articles.forEach { (article) -> () in ... realm.add(article, update: true) } } } }

Slide 25

Slide 25 text

Best practice [email protected] func getTimeline() { ... request.performRequestWithHandler { (data, response, error) -> Void in if let error = error { self.showAlert(error.localizedDescription) return } let articles = try NSJSONSerialization.JSONObjectWithData(data, options: []) let realm = try! Realm() try! realm.write { articles.forEach { (article) -> () in ... realm.add(article, update: true) } } } } فٓ؎ؤؗ٦׾ⵃ欽׃ג 鷄⸇،حفر٦ز 傀㶷ך3FTVMUTכ荈⹛涸ח 剑倜ךⰻ㺁ח刿倜ׁ׸׷

Slide 26

Slide 26 text

Migration [email protected]

Slide 27

Slide 27 text

Migration Tips [email protected] let config = Realm.Configuration(schemaVersion: 1, migrationBlock: { (migration, oldSchemaVersion) in migration.enumerate("") { (oldObject, newObject) in ... } }) Realm.Configuration.defaultConfiguration = config let realm = try! Realm()

Slide 28

Slide 28 text

Migration Tips [email protected] let config = Realm.Configuration(schemaVersion: 1, migrationBlock: { (migration, oldSchemaVersion) in migration.enumerate("") { (oldObject, newObject) in ... } }) Realm.Configuration.defaultConfiguration = config let realm = try! Realm()

Slide 29

Slide 29 text

Migration Tips [email protected] let config = Realm.Configuration(schemaVersion: 1) Realm.Configuration.defaultConfiguration = config let realm = try! Realm()

Slide 30

Slide 30 text

Migration Tips [email protected] class User: Object { dynamic var id = 0 dynamic var name = "" } class User: Object { dynamic var id = 0 dynamic var name = "" dynamic var age 0 }

Slide 31

Slide 31 text

Migration Tips [email protected] let config = Realm.Configuration(schemaVersion: 1) Realm.Configuration.defaultConfiguration = config let realm = try! Realm() "

Slide 32

Slide 32 text

Migration Tips [email protected] let config = Realm.Configuration(schemaVersion: 1, migrationBlock: { (migration, oldSchemaVersion) in migration.enumerate(User.className()) { (oldObject, newObject) in newObject![“age"] = 18 } }) Realm.Configuration.defaultConfiguration = config let realm = try! Realm() "

Slide 33

Slide 33 text

Migration Tips [email protected] class User: Object { dynamic var id = 0 dynamic var firstname = "" dynamic var lastname = "" } class User: Object { dynamic var id = 0 dynamic var fullname = "" }

Slide 34

Slide 34 text

Migration Tips [email protected] let config = Realm.Configuration(schemaVersion: 1, migrationBlock: { (migration, oldSchemaVersion) in migration.enumerate(User.className()) { (oldObject, newObject) in let firstname = oldObject!["firstname"] as! String let lastname = oldObject!["lastname"] as! String newObject!["fullname"] = firstname + lastname } }) Realm.Configuration.defaultConfiguration = config let realm = try! Realm() "

Slide 35

Slide 35 text

Reorder table view [email protected]

Slide 36

Slide 36 text

Basic solution [email protected] class Article: Object { dynamic var name = "" ... dynamic var order = 0 // ฒ΂ସ͑ͷͨΊͷΧϥϜ͕ඞཁ }

Slide 37

Slide 37 text

Basic solution [email protected] override func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) { try! realm.write { let sourceObject = objects[sourceIndexPath.row] let destinationObject = objects[destinationIndexPath.row] let destinationObjectOrder = destinationObject.order if sourceIndexPath.row < destinationIndexPath.row { // ্͔ΒԼʹҠಈͨ͠৔߹ɺؒͷ߲໨Λ্ʹγϑτ for index in sourceIndexPath.row...destinationIndexPath.row { let object = objects[index] object.order -= 1 } } else { // Լ͔Β্ʹҠಈͨ͠৔߹ɺؒͷ߲໨ΛԼʹγϑτ for index in (destinationIndexPath.row..

Slide 38

Slide 38 text

Best Practice: List is ordered [email protected] class ArticlesWrapper: Object { let articles = List }

Slide 39

Slide 39 text

Best Practice: List is ordered [email protected] override func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) { try! realm.write { let sourceObject = objects[sourceIndexPath.row] objects.removeAtIndex(sourceIndexPath.row) objects.insert(sourceObject, atIndex: destinationIndexPath.row) } }

Slide 40

Slide 40 text

Table view sections [email protected]

Slide 41

Slide 41 text

Slide 42

Slide 42 text

Best Practice: List is ordered [email protected] class Task: Object { dynamic var name = "" dynamic var notes = "" dynamic var createdAt = NSDate() dynamic var plannedAt = NSDate() dynamic var isCompleted = false }

Slide 43

Slide 43 text

Basic solution [email protected] class TableViewController: UITableViewController { ... var objectsBySection = [Results]() override func viewDidLoad() { super.viewDidLoad() ... for section in sectionTitles { let unsortedObjects = realm.objects(Task.self) let sortedObjects = unsortedObjects.sorted("date", ascending: true) objectsBySection.append(sortedObjects) } } override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return sectionTitles.count } override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return sectionTitles[section] } override func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int { return Int(objectsBySection[section].count) }

Slide 44

Slide 44 text

Best Practice: Use relationships [email protected] class TaskWrapper: Object { dynamic var date: String = "" // DD MM, YYYY dynamic var tasks = List() override class func primaryKey() -> String { return "date" } }

Slide 45

Slide 45 text

Best Practice: Use relationships [email protected] let dateString = dateFormatter.stringFromDate(task.createdAt) var dueDate = realm.objectForPrimaryKey(DueDate.self, key: dateString) if dueDate == nil { dueDate = DueDate() dueDate.date = dateString try! realm.write { realm.add(dueDate, update: true) } } dueDate.tasks.append(task)

Slide 46

Slide 46 text

Best Practice: Use relationships [email protected] override func numberOfSectionsInTableView(tableView: UITableView) -> Int { let realm = try! Realm() let sections = realm.objects(TaskWrapper) return sections.count }

Slide 47

Slide 47 text

1:1 inverse relationship [email protected]

Slide 48

Slide 48 text

1:1 inverse relationship [email protected] class Parent: Object { let children = List() } class Child: Object { let parents = LinkingObjects(fromType: Parent.self, property: "children") }

Slide 49

Slide 49 text

1:1 inverse relationship [email protected] class Child: Object { private let parents = LinkingObjects(...) var parent: Parent? { return parents.first } }

Slide 50

Slide 50 text

Mantle with Realm [email protected]

Slide 51

Slide 51 text

Mantle with Realm [email protected] MTLModel protocol The new protocol represents the basic behaviors expected from any model object, and can be used instead of the MTLModel class when inheritance is impossible, or to create more generic APIs. For example, conformance can be added to the objects from other persistence frameworks in order to use those objects in conjunction with Mantle’s adapters. Accordingly, MTLJSONAdapter has been updated to only depend on conformance, and no longer requires a MTLModel subclass in order to serialize or deserialize from JSON.

Slide 52

Slide 52 text

Mantle with Realm [email protected] @interface XYUser : RLMObject @property NSString *name; @property NSDate *createdAt; @end @implementation XYUser + (instancetype)modelWithDictionary:(NSDictionary *)dictionary error:(NSError **)error {...} - (instancetype)initWithDictionary:(NSDictionary *)dictionary error:(NSError **)error {...} + (NSSet *)propertyKeys {...} - (void)mergeValueForKey:(NSString *)key fromModel:(id)model {...} - (NSDictionary *)dictionaryValue {...} - (BOOL)validate:(NSError **)error {...} - (id)copyWithZone:(NSZone *)zone {...} + (NSDictionary *)JSONKeyPathsByPropertyKey {...} + (NSValueTransformer *)createdAtJSONTransformer {...} + (NSDateFormatter *)dateFormatter {...} @end

Slide 53

Slide 53 text

Mantle with Realm [email protected] @interface XYUser : RLMObject @property NSString *name; @property NSDate *createdAt; @end @implementation XYUser + (instancetype)modelWithDictionary:(NSDictionary *)dictionary error:(NSError **)error {...} - (instancetype)initWithDictionary:(NSDictionary *)dictionary error:(NSError **)error {...} + (NSSet *)propertyKeys {...} - (void)mergeValueForKey:(NSString *)key fromModel:(id)model {...} - (NSDictionary *)dictionaryValue {...} - (BOOL)validate:(NSError **)error {...} - (id)copyWithZone:(NSZone *)zone {...} + (NSDictionary *)JSONKeyPathsByPropertyKey {...} + (NSValueTransformer *)createdAtJSONTransformer {...} + (NSDateFormatter *)dateFormatter {...} @end

Slide 54

Slide 54 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] [email protected]

Slide 55

Slide 55 text

Realm Japan User Group Facebook [email protected]

Slide 56

Slide 56 text

Support Chat Slack [email protected]

Slide 57

Slide 57 text

Next meetup • 9/29ʢ໦ʣ 19:30~ • Sansanגࣜձࣾ [email protected]

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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