Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Realm Japan meetup #18

Realm Japan meetup #18

How to install Realm with Xcode 8 beta (CocoaPods & Carthage)
Migration tips
Order & sections with UITableView

Kishikawa Katsumi

August 17, 2016
Tweet

More Decks by Kishikawa Katsumi

Other Decks in Research

Transcript

  1. 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) kk@realm.io
  2. Realm Objective-C/Swift 1.0.2 • ϓϩύςΟ͕ଘࡏ͠ͳ͍ΫϥεΛอଘ͠Α͏ͱ͢Δͱྫ֎ʹ • write(_:)ϝιουͷϒϩοΫ಺ͰthrowͰ͖ΔΑ͏ʹ • όΠφϦαΠζ͕গ͠ݮগ •

    addNotificationBlock(_:, change:)Ͱॳճͷݺͼग़͠͸ඞ ͣ.Initial͕ݺ͹ΕΔΑ͏ʹ • ٯํ޲ͷؔ࿈͕มߋʹͳΔ৔߹ʹ௨஌͕ݺ͹Εͳ͍໰୊Λमਖ਼ jp@realm.io kk@realm.io
  3. Installing RealmSwift for Xcode 8 beta5 w/ Carthage kk@realm.io $

    echo SWIFT_VERSION=\"3.0\">swift3.xcconfig $ XCODE_XCCONFIG_FILE=`pwd`/swift3.xcconfig \ carthage update --no-use-binaries
  4. Installing RealmSwift for Xcode 8 beta5 w/ CocoaPods kk@realm.io 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
  5. Installing RealmSwift for Xcode 8 beta5 w/ CocoaPods kk@realm.io 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
  6. Installing RealmSwift for Xcode 8 beta5 w/ CocoaPods kk@realm.io 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
  7. Multi thread kk@realm.io 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 } } }
  8. Multi thread kk@realm.io 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 } } } !
  9. Basic solution kk@realm.io 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 } } } }
  10. Basic solution kk@realm.io 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 } } } }
  11. Best practice kk@realm.io var timeline: Results<Article>? 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) } } } }
  12. Best practice kk@realm.io var timeline: Results<Article>? 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() } }
  13. Best practice kk@realm.io 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) } } } }
  14. Best practice kk@realm.io 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כ荈⹛涸ח 剑倜ךⰻ㺁ח刿倜ׁ׸׷
  15. Migration Tips kk@realm.io let config = Realm.Configuration(schemaVersion: 1, migrationBlock: {

    (migration, oldSchemaVersion) in migration.enumerate("") { (oldObject, newObject) in ... } }) Realm.Configuration.defaultConfiguration = config let realm = try! Realm()
  16. Migration Tips kk@realm.io let config = Realm.Configuration(schemaVersion: 1, migrationBlock: {

    (migration, oldSchemaVersion) in migration.enumerate("") { (oldObject, newObject) in ... } }) Realm.Configuration.defaultConfiguration = config let realm = try! Realm()
  17. Migration Tips kk@realm.io class User: Object { dynamic var id

    = 0 dynamic var name = "" } class User: Object { dynamic var id = 0 dynamic var name = "" dynamic var age 0 }
  18. Migration Tips kk@realm.io 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() "
  19. Migration Tips kk@realm.io class User: Object { dynamic var id

    = 0 dynamic var firstname = "" dynamic var lastname = "" } class User: Object { dynamic var id = 0 dynamic var fullname = "" }
  20. Migration Tips kk@realm.io 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() "
  21. Basic solution kk@realm.io class Article: Object { dynamic var name

    = "" ... dynamic var order = 0 // ฒ΂ସ͑ͷͨΊͷΧϥϜ͕ඞཁ }
  22. Basic solution kk@realm.io 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..<sourceIndexPath.row).reverse() { let object = objects[index] object.order += 1 } } ɹɹɹɹɹɹɹɹ// Ҡಈͨ͠ηϧͷฒͼΛҠಈઌʹߋ৽ sourceObject.order = destinationObjectOrder } }
  23. Best Practice: List<T> is ordered kk@realm.io 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) } }
  24. Best Practice: List<T> is ordered kk@realm.io class Task: Object {

    dynamic var name = "" dynamic var notes = "" dynamic var createdAt = NSDate() dynamic var plannedAt = NSDate() dynamic var isCompleted = false }
  25. Basic solution kk@realm.io class TableViewController: UITableViewController { ... var objectsBySection

    = [Results<DemoObject>]() 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) }
  26. Best Practice: Use relationships kk@realm.io class TaskWrapper: Object { dynamic

    var date: String = "" // DD MM, YYYY dynamic var tasks = List<Task>() override class func primaryKey() -> String { return "date" } }
  27. Best Practice: Use relationships kk@realm.io 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)
  28. Best Practice: Use relationships kk@realm.io override func numberOfSectionsInTableView(tableView: UITableView) ->

    Int { let realm = try! Realm() let sections = realm.objects(TaskWrapper) return sections.count }
  29. 1:1 inverse relationship kk@realm.io class Parent: Object { let children

    = List<Child>() } class Child: Object { let parents = LinkingObjects(fromType: Parent.self, property: "children") }
  30. 1:1 inverse relationship kk@realm.io class Child: Object { private let

    parents = LinkingObjects(...) var parent: Parent? { return parents.first } }
  31. Mantle with Realm kk@realm.io MTLModel protocol The new <MTLModel> 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, <MTLModel> 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 <MTLModel> conformance, and no longer requires a MTLModel subclass in order to serialize or deserialize from JSON.
  32. Mantle with Realm kk@realm.io @interface XYUser : RLMObject<MTLModel, MTLJSONSerializing> @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<MTLModel>)model {...} - (NSDictionary *)dictionaryValue {...} - (BOOL)validate:(NSError **)error {...} - (id)copyWithZone:(NSZone *)zone {...} + (NSDictionary *)JSONKeyPathsByPropertyKey {...} + (NSValueTransformer *)createdAtJSONTransformer {...} + (NSDateFormatter *)dateFormatter {...} @end
  33. Mantle with Realm kk@realm.io @interface XYUser : RLMObject<MTLModel, MTLJSONSerializing> @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<MTLModel>)model {...} - (NSDictionary *)dictionaryValue {...} - (BOOL)validate:(NSError **)error {...} - (id)copyWithZone:(NSZone *)zone {...} + (NSDictionary *)JSONKeyPathsByPropertyKey {...} + (NSValueTransformer *)createdAtJSONTransformer {...} + (NSDateFormatter *)dateFormatter {...} @end
  34. 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/ jp@realm.io kk@realm.io