Swift+RealmでMacアプリケーション

5ad59da588bea31be31c83ab7994407c?s=47 Econa77
July 24, 2015

 Swift+RealmでMacアプリケーション

5ad59da588bea31be31c83ab7994407c?s=128

Econa77

July 24, 2015
Tweet

Transcript

  1. Swift+RealmͰMacΞϓϦέʔγϣϯ Realm Meetup #5

  2. ࣗݾ঺հ ݹྛ ढ़༞ גࣜձࣾυϫϯΰ Github : http://github.com/econa77 Twitter : http://twitter.com/econa77

    աڈ࡞ͬͨ΋ͷ REVENTIVE, Inc. Modelor, Inc. ResuPress, Inc. Close Presser Coincheck
  3. Agenda ɾClipyͱ͸ ɾRealmಋೖͷܦҢ ɾRealmͷಋೖ ɾTips ɾ໰୊఺

  4. ClipmenumΛ஌͍ͬͯ·͔͢ʁ

  5. Clipmenuͱ͸ ΫϦοϓϘʔυཤྺ & εχϖοτ ( http://www.clipmenu.com/ ) ςΩετ΍ը૾ͳͲ̔छྨͷΫϦοϓϘʔυܗࣜΛཤྺͱͯ͠ه࿥ՄೳͳMacΞϓϦɻ ه࿥ͨ͠ཤྺ͸ɺγϣʔτΧοτ౳Ͱ͍ͭͰ΋ϖʔετՄೳɻ εχϖοτ΋อଘ͠ϖʔετՄೳ

    ௕͍Objectice-CͷDelegate΋ҰൃͰϖʔετՄೳɻ ΧελϜΞΫγϣϯΛઃఆͯ͠jsͰ֦ுػೳΛॻ͚Δ ex. ϖʔετ࣌ʹจࣈྻΛ͍͡Δ
  6. CPU࢖༻཰͕๫૸ ݪҼ ɾه࿥͍ͯ͠ΔΦϒδΣΫτΛશͯϝϞϦ্ʹอଘ ɾ࠷ऴߋ৽͕2010೥ ɹMac OS X 10.6 Snow Leopard

    ɾϝχϡʔ͕දࣔ͞ΕΔͨͼʹDBɾϝϞϦʹΞΫη ɹεͯ͠࠶ੜ੒ ໰୊఺
  7. ClipMenu 1.0.0a1 released (2014/11/11) ɾΦϒδΣΫτΛDBʹ֨ೲ ɾϑϧϦϑΝΫλ(swift΁) ɾViewΛYosemiteʹ࠷దԽ εχϖοτػೳ͸ະϦϦʔε Clipmenu

  8. ɾίϯύΠϧͰ͖ͳ͍ ɾ࢖ͬͯΔϥΠϒϥϦ͕5೥લ͘Β͍ʹ։ൃ͕ͱ·ͬͯΔɻ ClipmenuͷObjective-C൛ͷίʔυ͕OSSͱͯ͠ެ։͞Ε͍ͯ·͢ http://github.com/naotaka/ClipMenu ϥΠϒϥϦͷ࡮৽΍طଘͷ໰୊ղܾͷͨΊswift΁ॻ͖௚͠ Φʔϓϯιʔε

  9. http://github.com/Clipy/Clipy http://clipy-app.com

  10. ɾཤྺΦϒδΣΫτΛϝϞϦͰ͸ͳ͘ϑΝΠϧͱͯ͠σΟεΫอଘ ɹ → ϑΝΠϧอଘύεΛDBʹ֨ೲ ɾطଘͷػೳʢΞΫγϣϯҎ֎ʣΛશͯ࠶ݱ ɾΠϯετʔϧdmgΛΧελϜ ɾObjective-C͔Β Swift ΁ ɾDBΛCoreData͔Β

    Realm ΁ มߋ఺
  11. DEMO

  12. ɾઃఆը໘΍εχϖοτฤूը໘ͷ׬શʹมߋ ɾΞΫγϣϯΛ෦෼తʹ෮׆ ɹˠjsͰॻ͘ͱ͔͸ࠓޙ΋ߟ͍͑ͯͳ͍ ݱঢ়͸҆ఆ൛ͱ͸͍͑ɺྼԽ൛Ͱ͔͠ͳ͍ εχϖοτΛ࣠ʹ։ൃ͍ͯ͘͠ ɾεχϖοτϚʔέοτʢԾʣͷ࣮ݱ ɹˠεχϖοτΛࣗ༝ʹΞοϓϩʔυɾμ΢ϯϩʔυͰ͖ ɹɹΔύοέʔδϚωδϟʔͷΑ͏ͳͳʹ͔Λ࡞Δ ͜Ε͔Β

  13. Realm DB

  14. RealmಋೖܦҢ ݱࡏɺ৽نΞϓϦ։ൃͰRealmಋೖΛݕ౼͍ͯ͠Δ͕ɺຊ൪౤ೖʹ͍͖ͳΓಋ ೖͱ͍͏Θ͚ʹ͸ߦ͔ͳ͍ ͦ͜Ͱɺຊ൪౤ೖͷ࣮ݧతͳҙຯΛࠐΊͯࠓճClipyʹ͸RealmΛಋೖ͍ͯ͠· ͢ɻ ࣾ಺Github͓͡͞ΜͳΒ͵Realm͓͡͞ΜΛ໨ࢦ͍ͨ͠

  15. ࠷ऴతʹ͸࣮ࡍʹϦϦʔε͢ΔiOSΞϓϦ΁ͷಋೖΛ໨ࢦ͍ͯ͠ΔͨΊɺiOS7 ରԠ͸·ͩඞཁͳͷͰɺObjective-C൛Λ࢖༻ ClipyͷରԠOS͸Mavericks͔ΒͳͷͰɺRealmSwiftΛ࢖༻Ͱ͖Δɻ ࢖༻όʔδϣϯ iOSͰRealmSwiftΛར༻͢Δʹ͸iOS8Ҏ্͕ඞਢ ϓϩδΣΫτ΁ͷΠϯετʔϧ͸CocoaPodsΛ࢖༻ Swift͔ΒRealmObjective-C൛Λ࢖༻͢Δʹ͸ผ్RLMSupportΛΠϯϙʔτ

  16. MacΞϓϦ͔ͩΒͱ͍ͬͯಛஈόά͸ͳ͍ ɹˠ جຊతʹ͸iOSͱಉ͡ Ή͠Ζ५୔ʹϝϞϦ͕͋ΔMacͷ΄͏͕RealmͷྗΛ׆͔͢͜ͱ͕Ͱ͖͍ͯΔ ࣗ෼ͱͯ͠͸ࠓޙMacΞϓϦΛ࡞Δͱͨ͠ΒRealmҎ֎͸ͳ͍ Realm + CocoaApplication

  17. Tips

  18. RLMResult RLMResult͸ৗʹ࠷৽ͷঢ়ଶ͕อͨΕ͍ͯΔ FetchedResultsControllerͱಉ͡Α͏ͳ࢖͍ํ͕Ͱ͖ΔͷͰɺTableviewͷ DataSourceͳͲʹ࢖༻͢Δͱඇৗʹศར ɹˠ σʔλ͕มߋ͞Εͯ΋reloadData()ΛݺͿ͚ͩͰߋ৽͕͔͔Δ private var clips: RLMResults?

    self.clips = CPYClip.allObjects().sortedResultsUsingProperty("updateTime", ascending: false) self.reloadData() let clips = CPYClip.allObjects().sortedResultsUsingProperty("updateTime", ascending: false)
  19. RLMArray͸಺෦Ͱॱ൪͕อূ͞Ε͍ͯΔ ॱ൪ͷೖΕସ͑Λߦ͍͍ͨ RLMArray - (void)moveObjectAtIndex:(NSUInteger)sourceIndex toIndex:(NSUInteger)destinationIndex; PullRequestΛݕࡧͯͨ͠Βࡢ೔ #2273 Ͱ࡞੒͞Ε͍ͯͨ dynamic

    var snippets = RLMArray(objectClassName: CPYSnippet.className())
  20. ΦϒδΣΫτʹมߋ͕͋ͬͨ৔߹ɺ௨஌Λड͚औΔ͜ͱ͕Ͱ͖Δɻ ͲͷΦϒδΣΫτ͕ߋ৽͕͔͔͔ͬͨ෼͔Βͳ͍ɻ ࠓճɺݱࡏ࣮૷தͷΞϓϦͰ͸རศੑ͕ͳ͍ͷͰɺ࢖༻͍ͯ͠ͳ͍ɻ Notification RLMRealm.defaultRealm().addNotificationBlock{ notification, realm in } ݱࡏɺIssueͰ্͕͍ͬͯΔͷͰߋ৽ΦϒδΣΫτ͕औΕΔΑ͏ʹͳΕ͹࢖༻͢Δ༧ఆɻ

  21. RealmͷΦϒδΣΫτݕࡧ͸̎छྨ͋ΔʢSwift͔ΒObjC൛Λ࢖༻͢Δ৔߹ͷΈʣ objectsWhereͷ಺෦࣮૷ ฦΓ஋ͷRLMResults͕Φϓγϣφϧͳͷ͔ɺͦ͏Ͱͳ͍ͷ͔ͷҧ͍ ݕࡧ objectsWithPredicate:(NSPredicate *)predicate objectsWhere(predicateFormat: String, _ args:

    CVarArgType...) public class func objectsWhere(predicateFormat: String, _ args: CVarArgType...) -> RLMResults { return objectsWithPredicate(NSPredicate(format: predicateFormat, arguments: getVaList(args))) } objectsWithPredicate:(NSPredicate *)predicate ɹɹɹɹɹɹɹɹɹ -> RLMResult? objectsWhere(predicateFormat: String, _ args: CVarArgType…) ɹ-> RLMResult
  22. ϦϨʔγϣφϧ class CPYFolder: RLMObject { // MARK: - Properties dynamic

    var index = 0 dynamic var enable = true dynamic var title = "" dynamic var snippets = RLMArray(objectClassName: CPYSnippet.className()) } class CPYSnippet: RLMObject { // MARK: - Properties dynamic var index = 0 dynamic var enable = true dynamic var title = "" dynamic var content = "" dynamic var folder: CPYFolder? { return linkingObjectsOfClass("CPYFolder", forProperty: "snippets").first as? CPYFolder } }
  23. RLMResults͕ৗʹ࠷৽ͷ஋Λ͍࣋ͬͯΔͨΊforͰ࡟আ΍ߋ৽Λߦ͏ͱॱ൪͕ͣ ΕΔ ࡟আɾߋ৽ internal func removeFolders() { let realm =

    RLMRealm.defaultRealm() let folders = CPYFolder.allObjects() for folder in folders { realm.transactionWithBlock({ () -> Void in realm.deleteObjects((folder as! CPYFolder).snippets) realm.deleteObject(folder) }) } }
  24. RLMResults͕ৗʹ࠷৽ͷ஋Λ͍࣋ͬͯΔͨΊforͰ࡟আ΍ߋ৽Λߦ͏ͱॱ൪͕ͣ ΕΔ ࡟আɾߋ৽ internal func removeFolders() { let realm =

    RLMRealm.defaultRealm() let folders = CPYFolder.allObjects() for folder in folders { realm.transactionWithBlock({ () -> Void in realm.deleteObjects((folder as! CPYFolder).snippets) }) } realm.transactionWithBlock { () -> Void in realm.deleteObjects(folders) } }
  25. RealmͰͰ͖Δ͚ͩ៉ྷͳEnum Enum class CPYClip: RLMObject { // MARK: - Properties

    enum DataStatus: String { case Status1 = "status1" case Status2 = "status2" } dynamic var localStatus = DataStatus.Status1.rawValue internal var status: DataStatus { get { return DataStatus(rawValue: self.localStatus) ?? .Status1 } set { self.localStatus = newValue.rawValue } } }
  26. DBϑΝΠϧͷ҉߸ԽʹରԠ͍ͯ͠Δ iOS৔߹Ͱ΋DBϑΝΠϧ͕Ӿཡ͞ΕΔ৔߹͸͋ΔͷͰɺϢʔβͷ৘ใͳͲɺݟΒ Εͯ͸͍͚ͳ͍σʔλΛอଘ͢Δ৔߹͸҉߸ԽΛߦ͏ ҉߸Խ MacΞϓϦ͸୭Ͱ΋ӾཡՄೳͳҐஔʹDBϑΝΠϧ͕ஔ͔ΕΔͷͰͰ͖Ε͹҉߸Խ ͓ͯ͘͠ NSMutableData *key = [NSMutableData

    dataWithLength:64]; SecRandomCopyBytes(kSecRandomDefault, key.length, (uint8_t *)key.mutableBytes); [RLMRealm setEncryptionKey:key forRealmsAtPath:RLMRealm.defaultRealmPath]; RLMResults *dogs = [[Dog objectsWhere:@"name contains 'Fido'"]];
  27. ໰୊఺

  28. ໰୊఺ ɾNSOutlineView ɾCustom Initializer ɾNSDataͷnilαϙʔτ ɾNSDate ɾDeleteRule

  29. NSOutlineViewͷDataSourceͱͯ͠ RealmObjectΛ࢖͑ͳ͍ NSOutlineView(ݕূத) func outlineView(outlineView: NSOutlineView, numberOfChildrenOfItem item: AnyObject?) ->

    Int { if item == nil { return Int(self.folders!.count) } else if let folder = item as? CPYFolder { return Int(folder.snippets.count) } return 0 } NSOutlineViewॳΊͯ࢖͏ͷͰ࢖͍ํ͕ؒҧͬͯ ͍Δ͚͔ͩ΋͠Ε·ͤΜ
  30. ΦϒδΣΫτʹΧελϜInitializerͷఆٛ Custom Initializer override init() { super.init() } init(title: String)

    { self.title = title super.init() } // MARK: Primary Key override class func primaryKey() -> String { return "dataHash" } CPYClip(forPrimaryKey: "") forPrimaryKeyϝιου͕ݺ΂ͳ͍
  31. αϜωΠϧը૾Λαϙʔτ͢ΔͨΊʹը૾ΛDBʹೖΕ͔ͨͬͨ nilαϙʔτ͕β൛Ͱެ։த ࠓޙͷclipyͷόʔδϣϯΞοϓ Ͱద༻༧ఆ NSDataͷnilαϙʔτ ͦͷଞϓϩδΣΫτʹؔͯ͠͸ɺ ը૾ΛσΟεΫʹอଘͯ͠ύεͷ ΈΛೖΕΔํࣜ

  32. NSDate͸ϛϦඵؙ͕ΊΒΕΔ αʔόଆͱͷ௨৴΋ߟ͑Δͱ࢓༷Λ߹Θ͓͖͍ͤͯͨ NSDate let unixTime = NSDate().timeIntervalSince1970 let clip =

    CPYClip() clip.dataPath = path clip.title = title clip.dataHash = String(hash) clip.updateTime = unixTime clip.primaryType = clipData.primaryType ?? "" RealmͰ࣌ؒΛѻ͏ͱ͖͸શͯUNIXTimeͰѻ͍౎౓ม׵
  33. DeleteRule͕ઃఆͰ͖ͳ͍ͨΊɺ਌Λ࡟আ͢Δ࣌͸ɺࣗ෼Ͱ࡟আ͢Δɻ Delete Rule internal func removeFolders() { let realm =

    RLMRealm.defaultRealm() var folders = CPYFolder.allObjects() for folder in folders { realm.transactionWithBlock({ () -> Void in realm.deleteObjects((folder as! CPYFolder).snippets) }) } realm.transactionWithBlock { () -> Void in realm.deleteObjects(folders) } }
  34. ·ͱΊ ɾClipy͸͜Ε͔Β΋ศརͳMacΞϓϦέʔγϣϯΛ௥ٻ͍͖͍ͯͨ͠ͷͰɺͲ ɹͳͨͰ΋ؾ͍ͮͨ఺΍όά͕͋Ε͹Issue΍PullRequestΛૹ͍ͬͯͩ͘͞ ɾֶशίετ΋ͦͷଞDBʹൺ΂Δͱ͔ͳΓ௿͘ɺ։ൃ΋׆ൃతͳͷͰͲΜͲ ɹΜಋೖ͍͖͍ͯͨ͠ ɾVersion1.0ʹ౸ୡ͍ͯ͠ͳ͍ͷͰɺૣ҆͘ఆ൛ͱͯ͠ϦϦʔεͯ͠΋Β͑͏ ɹͱخ͍͠