Last active
August 14, 2016 03:51
-
-
Save brentsimmons/47fa9c49cf4efb8e024541d651b6ebd2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//: Playground - noun: a place where people can play | |
import Cocoa | |
// When you’re downloading objects from the web, it’s common to need to merge changes | |
// from the server to already-existing local objects. (If your data model allows for | |
// mutable objects, as with Core Data, that is.) | |
// | |
// The below is a Swift translation of how I’ve done this in Objective-C. | |
// Note that it works just fine in Swift — though it does require NSObject subclasses. | |
// | |
// The part I like is that updateLocalObjectWithServerObject is reusable | |
// (and I have reused my equivalent Objective-C code). | |
// It doesn’t care what the objects are, or whether they’re of the same type, | |
// and it doesn’t care what the types of the values are. | |
// | |
// An argument against is that it uses strings — see mergeablePropertyNames. | |
// Type one of those wrong, and you get a runtime exception. | |
// My counter to that is that you’ll find that bug very, very quickly. | |
// Even your testers won’t see it. | |
// | |
// My wish is that I could do this same thing — or something very much like it — | |
// in pure Swift (minus NSObject), and that it would work with structs as well as classes. | |
class LocalObject: NSObject { | |
var dog = "Fido" | |
var cat = "Hunter" | |
var zebra = "Mr. Stripes" | |
var numberOfAnimals = 17 | |
var fedTheTigers = false | |
var attendingDoctors: [String]? | |
let zoo = "On My Mac" | |
static let mergeablePropertyNames = ["dog", "cat", "zebra", "numberOfAnimals", "fedTheTigers", "attendingDoctors"] | |
} | |
class ServerObject: NSObject { | |
var dog = "Rex" | |
var cat = "Hunter" | |
var zebra = "Mr. Stripes" | |
var numberOfAnimals = 33 | |
var fedTheTigers = true | |
var attendingDoctors = ["Smith", "Tennant", "Capaldi"] | |
let dateDownloaded = NSDate() | |
} | |
func valuesAreEqual(value1: AnyObject?, _ value2: AnyObject?) -> Bool { | |
if let value1 = value1, value2 = value2 { | |
return value1.isEqual(value2) | |
} | |
if value1 == nil && value2 == nil { | |
return true | |
} | |
return false | |
} | |
func updateLocalObjectWithServerObject(localObject: AnyObject, serverObject: AnyObject, propertyNames: [String]) -> NSDictionary { | |
// Returns a dictionary with the changes. The changes can then be used for notifications, updating the database, etc. | |
let changeDictionary = NSMutableDictionary() | |
propertyNames.forEach { (onePropertyName) in | |
let localValue = localObject.valueForKey(onePropertyName) | |
let serverValue = serverObject.valueForKey(onePropertyName) | |
if valuesAreEqual(localValue, serverValue) { | |
return | |
} | |
localObject.setValue(serverValue, forKey: onePropertyName) | |
changeDictionary[onePropertyName] = serverValue | |
} | |
return changeDictionary.copy() as! NSDictionary | |
} | |
let x = LocalObject() | |
let y = ServerObject() | |
let changes = updateLocalObjectWithServerObject(x, serverObject: y, propertyNames: LocalObject.mergeablePropertyNames) | |
print(changes) | |
// Prints: | |
//{ | |
// attendingDoctors = ( | |
// Smith, | |
// Tennant, | |
// Capaldi | |
// ); | |
// dog = Rex; | |
// fedTheTigers = 1; | |
// numberOfAnimals = 33; | |
//} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment