神刀安全网

Core Data Type Safety with Swift

Core Data has had a long history, and it has emerged as the de facto persistence solution on iOS. An inescapable part of its past is its extremely dynamic nature, and developers’ efforts to get more help from the compiler in the form of code generation.

Handcrafted Managed Objects

Originally, Apple provided very little support in generating your managed object files. There was a menu option that would copy the method declarations to your clipboard and let you paste the method declarations into your model files. This was done one by one for every entity in your model file.

mogenerator

mogenerator was the first Core Data code generation solution to gain widespread adoption. Mogenerator generates two subclasses per entity: one that contained auto-generated code, and another for your application code. The auto-generated file had basic stubs for all of the properties declared in the Core Data model, as well as a few more obscure features:

  • Automatically synthesize the KVC-compliant methods for to-many relationships that were dynamically supported by the runtime, but not widely known to developers.
  • Provide automatic boxing support via generated primitive properties that relayed to the original property type.
  • Provide NSManagedObjectID subclasses per entity to specify when a specific entity’s object ID was expected.

Xcode Support

Apple soon caught on to this and decided to roll support for code generation into Xcode. It didn’t have all of the bells and whistles that mogenerator did, but it was built in, and would generate an Objective-C category full of @dynamic property declarations and KVC-compliant methods for every entity.

There was also a checkbox, “Use scalar properties for primitive data types,” that a few developers found. This would generate primitive properties, instead of object properties, for scalar types (i.e. integers, Booleans) in the Core Data model. This worked as long as you didn’t need to specify the optionality of the property, since primitive types in Objective-C don’t differentiate betweenand nil . Another issue was Xcode would generate NSTimeInterval properties instead of NSDate , which was always disappointing. The combination of these two issues gave this option limited utility in practice.

Swift and Core Data

Xcode also supports Swift code generation, but I don’t think developers should use it. First off, the amount of code you have to write to use Core Data with Swift is less than with Objective-C, since there are not separate interface and implementation files and the property syntax is simpler. It’s not that hard to do by hand, as we’ll see. Second, types are so much more important in Swift, and NSManagedObject is actually incredibly smart when it comes to types and Swift.

Primitive Types

Before Swift, there was no way to express optionality of primitive types, so many properties had to use NSNumber to declare the lack of a value. All Swift types support optionality, so there’s no need to use NSNumber or other Foundation properties in Core Data with Swift. You may need NSDecimalNumber for decimal types, but prefer the native Swift types whenever you can. Also, look into default values and consider removing optionality altogether where possible.

Optionals

All of Xcode’s generated properties are of Optional type. This makes sense at first glance, because who knows if the property has been set, right? If optionality is an important attribute of your properties, then keep it; however, if you don’t care, get rid of it! Core Data’s dynamic runtime will intelligently create a real instance of an object, even if it hasn’t been set in the database.

class MyEntity:NSManagedObject {       // Returns 0 (or the default value) if not set     @NSManagedvar number: Int32       // Returns "" (or the default value) if not set     @NSManagedvar string: String       // Returns empty set if not set     @NSManagedvar relationship: NSSet       // What does an optional association really mean here?     @NSManagedvar relationship: NSSet? } 

That’s not to say that Optional values have no place in your model, but remember that you don’t have to use them!

Int

Core Data requires size information when specifying an integer. Be sure not to represent a 64-bit integer from Core Data as Int in swift. Int uses the platform integer, so on older devices, this is still 32 bits, and overflowing the integer will cause a crash on those devices. It is safe to use Int for 32-bit integers and smaller. This is helpful since Int is a bit more friendly in Swift than its sized relatives. But if you must use 64-bit integers in Core Data, you must use Int64 in Swift!

Generics

By default, to-many relationships will be generated as NSSet? . But who can deal with typeless containers these days? Use the native Swift Set type instead:

class MyEntity:NSManagedObject {     @NSManagedvar relationship: Set<OtherEntity>? } 

And while we’re at it, let’s get rid of the optionality. After all, what does a nil set mean in terms of an association that an empty set doesn’t?

class MyEntity:NSManagedObject {     @NSManagedvar relationship: Set<OtherEntity> } 

Property List Storage

It is easy to add a property with plist-compatible data types via the Transformable type in the Core Data editor. This is not new to Swift, but what was only possible before now becomes easy and helpful with a nice type system, as opposed to the Objective-C generated id .

Core Data Type Safety with Swift

Set the Attribute Type of a Core Data model object property to Transformable to be able to populate it with any plist-compatible model object.

class Entity:NSManagedObject {     @NSManagedvar imageURLBySizes: [String: String] } 

Type On!

If you’re using Core Data with Swift, I hope this inspires you to revisit you models and reduce the amount of force casting and optional unwrapping in your code. If anyone comes up with a better tool that solves this problem cleanly we’ll be sure to update this post to let you know.

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Core Data Type Safety with Swift

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址