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

    addNotificationBlock(_:, change:)Ͱॳճͷݺͼग़͠͸ඞ ͣ.Initial͕ݺ͹ΕΔΑ͏ʹ • ٯํ޲ͷؔ࿈͕มߋʹͳΔ৔߹ʹ௨஌͕ݺ͹Εͳ͍໰୊Λमਖ਼ [email protected] [email protected]
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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 } } }
  8. 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 } } } !
  9. 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 } } } }
  10. 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 } } } }
  11. Best practice [email protected] 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 [email protected] 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 [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) } } } }
  14. 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כ荈⹛涸ח 剑倜ךⰻ㺁ח刿倜ׁ׸׷
  15. 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()
  16. 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()
  17. 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 }
  18. 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() "
  19. 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 = "" }
  20. 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() "
  21. Basic solution [email protected] class Article: Object { dynamic var name

    = "" ... dynamic var order = 0 // ฒ΂ସ͑ͷͨΊͷΧϥϜ͕ඞཁ }
  22. 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..<sourceIndexPath.row).reverse() { let object = objects[index] object.order += 1 } } ɹɹɹɹɹɹɹɹ// Ҡಈͨ͠ηϧͷฒͼΛҠಈઌʹߋ৽ sourceObject.order = destinationObjectOrder } }
  23. Best Practice: List<T> 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) } }
  24. Best Practice: List<T> 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 }
  25. Basic solution [email protected] 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 [email protected] 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 [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)
  28. Best Practice: Use relationships [email protected] override func numberOfSectionsInTableView(tableView: UITableView) ->

    Int { let realm = try! Realm() let sections = realm.objects(TaskWrapper) return sections.count }
  29. 1:1 inverse relationship [email protected] class Parent: Object { let children

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

    parents = LinkingObjects(...) var parent: Parent? { return parents.first } }
  31. Mantle with Realm [email protected] 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 [email protected] @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 [email protected] @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: [email protected] • # Slack: slack.realm.io/ [email protected] [email protected]