Quantcast
Channel: Core Data – Michael Tsai
Viewing all 217 articles
Browse latest View live

Using Core Data With Swift

$
0
0

Tom Harrington:

Both Core Data and Swift include the concept of an optional value. But when Xcode generates subclasses, it doesn’t consider whether Core Data thinks the value is optional when generating the Swift file. It generates non-optional properties every time. This conflict means that you end up a Swift non-optional property that could reasonably have a nil value. The compiler sees that the property is not optional, so it doesn’t mind that you aren’t checking this (in fact, Swift rules mean it’s not possible to check, because the property is not optional). This is exactly the kind of problem Swift’s compiler is supposed to catch for you, but here it can’t.

This can lead to crashes.

If you’re using mogenerator, you’re covered for Core Data optionals. It makes sure Core Data optionals become Swift optionals. I’d take it a step farther and make all properties optional in Swift even if they’re required by Core Data. Core Data doesn’t enforce the “required” rule until you save changes, so even non-optional attributes can legally be nil at almost any time.

[…]

Although the documentation could be read as meaning that @NSManaged is required, it actually isn’t. It’s only needed if you’ll be letting Core Data handle the accessors. If you’re providing your own, drop it. Core Data’s accessor magic is not documented but it seems you can’t just override it like you’d override other methods.


Zarra’s Core Data Stack

$
0
0

Marcus Zarra creates a private queue context for writing to disk and a main queue (child) context for all user interaction:

To protect our main thread, we call -addPersistentStoreWithType: configuration: URL: options: error: in a dispatched background block. This will allow our -initializeCoreData method to return immediately, even if the persistent store needs to do some additional work. However, the user interface needs to know when it is safe to access the persistence layer. Therefore we need to use the callback block that was given to us.

[…]

The proper way to get access to the persistence controller is to inject it into each view controller as they are built and accessed.

[…]

The occasions where I don’t use this stack usually involve large data manipulation. When I need to process a tremendous amount of data into the Core Data stack and that data can be isolated away from the User Interface.

Update (2018-09-04): Stichting CocoaHeadsNL:

Dmitrii Ivanov gives us an insight view of the experience that the Qardio iOS team has gained over the years by using Core Data. He explains the issues they’ve had with Core Data, the different stacks you can use and their implementation and performance differences.

WWDC 2015 Links

$
0
0

General:

Mac:

iOS:

Swift:

Core Data Bugs

$
0
0

Almost four years ago, Dev reported a bug with Core Data’s NSOrderedSet generated accessors (via Ling Wang).

DaGaMs, in 2013:

I just brought this up with an Apple engineer during one of the CoreData Lab sessions at WWDC. They acknowledge the issue and that it’s a genuine bug, and from what I’ve seen it has the “critical” status, but of course there’s no promise as to when they’ll fix it. I don’t think it’ll be fixed in iOS6/Mountain Lion. I think it’d be good to duplicate this radar further. Currently it has about 25 dup’s, the more the better!

It seems like an important and straightforward bug to fix, but it’s still present in iOS 9.

Another bug, reported by Michael Gorbach (tweet):

We have found a reproducible CD deadlock that can occur when using a fetched results controller with a “complex” (i.e. either multi-level or “synthesized” (not in the database) sectionNameKeyPath). This occurs specifically with a stack that has a top-level background (private queue) writing context, where the main thread context is a child of this context.

Changes to CD (object creations and updates) as well as fetch requests, are taking place sequentially on background “import” contexts (private queue contexts). These contexts are also children of the top-level private queue writing context. If, while these CD changes and fetch requests are taking place in the background, the main thread Fetched Results Controller is asked to perform it’s initial fetch, a deadlock results.

Dynamic Swift

$
0
0

Lee Morgan:

We’ll go ahead and extend our KVC protocol and add our default implementation.

extension KVC {
    
    func valueForKey(key : String) -> Any? {
    
        let mirror = reflect(self)
        
        for index in 0 ..< mirror.count {
            let (childKey, childMirror) = mirror[index]
            if childKey == key {
                return childMirror.value
            }
        }
        return nil
    }
}

David Owens II has a different implementation that also handles setting values:

As you might be gathering, the basic premise is to use a backing store to maintain our values and type information. The implementation can then verify that the data coming in is correct.

David Owens II:

But wait… if we can shadow the functions and replace them with our own implementations, then this means that method swizzling is back on the table!

There are several caveats, though.

Adrian Kashivskyy:

Remember that reflection in Swift is currently read-only and there’s no way to modify your program at runtime (with Objective-C-derived classes being an exception as you can still class_addMethod() in Swift).

Brent Simmons asks how to instantiate an arbitrary class at runtime.

David Owens II:

The same way as C++, an ugly switch statement!

Wil Shipley:

On the latest Swift you have to add the word “init” to make this more explicit. Then it works. e.g:

let a:P = clsA.init(i:1)

Brent Simmons:

Jim takes this one step further: what if all you have is the class name as a string?

Alas, that’s currently only possible using Objective-C classes. There is no NSClassFromString() for Swift. [Update (2015-07-23): Actually, there is. See the comments below.]

David Owens II:

Xcode 7 Beta 4 is out and it is a doozy! One of the changes is that performSelector is now available from Swift. Now, this isn’t going to make your Swift types dynamic all of a sudden. However, what it does open the door for, is writing both your ObjC-style code and your Swift code all in the same language: Swift.

Brent Simmons:

Here’s the deal I’m willing to make: to make my code more elegant (read: smaller, easier to maintain, reusable), I’m willing to let it crash if I’ve configured things incorrectly.

[…]

So my case is that Swift itself needs things like this. If not a clone of KVC, then something very much like it.

Rob Rhyne:

When Apple announced the Swift programming language in 2014, there were questions about the future of frameworks that depended heavily on the dynamic nature of Objective-C. Frameworks such as Core Data marshall objects with type dependencies determined at runtime. The strict type checks required by the Swift compiler appeared in conflict with Core Data.

[…]

It turns out the answer to one question begat the solution to the other. By turning this class extension into a protocol and with a clever use of typealias, I resolved the insidious casting problem while maintaining type safety. Protocols to the rescue!

In other words, there are ways to use Core Data from Swift in a type-safe way. But it would still be impossible to write Core Data itself in pure Swift.

A Eulogy for Objective-C

$
0
0

Aaron Hillegass (comments: 1, 2):

The wonderful thing about Objective-C is that it’s so dynamic. As we start moving into languages that are a little bit more uptight about such things, it’s nice to take a moment and think about the huge benefits that we get from some of this.

[…]

Loose typing made a lot of things that were difficult in other languages much easier, or possible. It also made bugs that didn’t exist in other languages possible as well. And you embrace that as an Objective-C programmer. You’re like, “This is a language for smart, pedantic, uptight people. I’m going to be very careful and do the right thing when I’m typing in names.”

[…]

One of the things that made the performance of Core Data so great, and made this faulting mechanism so seamless, is the ability to do isa swizzling. Once again, this could be very dangerous, but in the right hands it was a really powerful mechanism.

Another thing that you could do was actually create classes at runtime. It was pretty rare, but this is actually what made key-value observing possible.

[…]

Here’s one that people take for granted at this point, but it’s something that at the time was crazy: categories. The idea that I could take a class that NeXT had sent me, add methods to it, and then use that inside my program - that was really, really weird in object-oriented languages at that time. And it really scared Java people. […] As a result, not everybody had to write their own NSString class. Which is a really common problem for a lot of languages.

Git as a Document Format

$
0
0

Wil Shipley:

Undo and redo was sort of part of Core Data, but they tried to do it at the lowest level, where any time you changed the database, it just registered an undo event. This turned out to be a horrible idea. If you do any kind of housekeeping such as storing the user’s window position in the database, that suddenly becomes undoable. So, it turns out, if you have any auxiliary objects that get created, that also turns undoable. It’s not a good way to do undo.

[…]

In our perfect world of documents, we want fast loads. We don’t want to be forced to load all our data at once. We want fast saves. Fast is going to be one of the themes of our perfect world. Again we don’t want to re-save large blobs, and we’d love to have an editable format. We want autosaves to be instant, but not blow away the previous states of the document like Preview does. Undo and redo also need to be instant and never be corrupted by bad coding. We’d like them to be persistent, because that’s really cool and provides the ability to prune them.

For security reasons, you don’t necessarily want every version of your document in the document; we’ve learned that from the Microsoft Word exploits. The backup of our perfect file format should play nicely with Time Machine, which means that it shouldn’t have one giant monolithic file that changes by one byte and restarts the backup process. And, it should be incredibly easy to implement, because this is our perfect world, so why not?

[…]

As I said, you still need to decide on the file format for the control files; Git isn’t a file format that you would parse and turn into a series of drawing commands, it just gives you the files and their blobs really easily.

The Big Nerd Ranch Core Data Stack

$
0
0

Robert Edwards notes that the Nested Managed Object Context Pattern has some cons:

  • Slower than Shared Persistent Store Coordinator Pattern when inserting large data sets
  • awakeFromInsert being called on NSManagedObject subclasses for each context in the parent chain
  • Merge policies only apply to a context saving to a store and not to its parent context

[…]

Since saving an NSManagedObjectContext will only propagate changes up a single level to the parentContext, the Big Nerd Ranch Core Data Stack listens for save notifications and ensures that the changes get persisted all the way up the chain to your store.

You may sometimes need to perform large import operations where the nested context performance would be the bottleneck. For that, we’ve included a function to vend you a managed object context with its own stack newBatchOperationContext(setupCallback: CoreDataStackBatchMOCCallback). This follows the pattern outlined in Shared Store Stack Pattern.


Core Data in El Capitan

$
0
0

There are again no Core Data release notes this year, but there is WWDC 2015 Session 220 (video, PDF):

Previously you may have used -hasChanges, this was a rather basic dirty flag, if you touch the object, we would mark it dirty. But with -hasPersistentChangedValues we’ll ensure that the properties on the object are different than what’s in the persistent store ensuring you don’t have any false positives.

Also new on NSManagedObject is -objectIDsForRelationsipNamed: for relationship named. This is ideal for working with large relationships mainly because we won’t materialize the entire relationship in memory rather we’ll return to typed array of object IDs to you. This allows you to go through these object IDs and work with your objects in smaller sizes.

[…]

Well Core Data has you covered this year, simply tell us which attributes should be unique across any entity and we’ll make sure all instances of that entity keep that unique attribute, be it email addresses, part numbers, UPC, you name it, we’ll make sure it is unique across all instances.

[…]

NSBatchDeleteRequest works like NSBatchUpdateRequest in that it acts directly in the persistent store without loading any objects into memory.

[…]

Whenever you have a store that’s created or migrated or just opened on the new iOS from an older version the managed object model used to create it is cached into the store and it is used by lightweight migrations when they fail to find appropriate source model as sort of a last-ditch effort.

Zachary Orr:

And there you have it! That’s all you need to get unique constraints working in Core Data. In my demo project, I’ve used a NSFetchedResultsController to show where unique constraints will not work well. If you’re displaying data using a fetched results controller, you’ll still see entities with non-unique properties, since conflict resolution only happens when saving our managed object context, and fetched results controllers work with in-memory objects.

Jeremiah Jessel:

refreshAllObjects This refreshes all the objects in the context while preserving the unsaved changes. The references will remain valid and it will break any retain cycles that may have been inadvertently created.

Florian Kugler and Daniel Eggert:

When using multiple managed object contexts concurrently, you also have to handle race conditions when deleting objects. iOS 9 and OS X 10.11 have a convenient solution for this problem in the form of the context’s shouldDeleteInaccessibleFaults property. However, this convenience comes with tradeoffs. Alternatively you can implement robust deletion using a two-step deletion process.

Despite all the talk about how Core Data is not a database, it seems to be continually growing database-type features. And that’s a good thing. Why not use the power of the underlying SQLite engine?

The Story of NetNewsWire

$
0
0

Rebekah Wolf:

Still feeling that iCloud would be the best fit once it was fully functional, the product team shifted their focus to developing Kaleidoscope 2 while they waited for Apple to work out the issues.

“By the time we shipped Kaleidoscope 2, we had internal discord around whether or not it was worth working on NetNewsWire anymore,” says Pasco, detailing the ill-fated turn of events. “Bil [Moorehead, CTO], George [Dick, COO], and I were for it, and most of the business management team was strongly against it. This, with some major internal problems, resulted in us focusing on client work and shelving product for a while.”

It’s a shame that the whole product was put on hold for a feature that some of us don’t care that much about.

Previously: NetNewsWire 4.0.

Generating Core Data Swift

$
0
0

Human Friendly:

There are two [Xcode] generation options, with “Use scalar properties for primitive data types” you get usefully typed integers, floats, doubles and bools but lose the expression to express optionals/nil values. This is presumably due to the limitations of the Objective-C based API. It also expresses date types as NSTimeIntervals (Doubles) rather than NSDates. The other option will generate with objects so you will get NSDates but for number values and Booleans you will get NSNumbers which lose information about whether it is a floating point type, integer or boolean.

[…]

The Core Data model file is actually a very simple XML file and parsing it is relatively straightforward. I’ve written a quick (but brittle so far) parser using NSXMLParser. This means that I can easily get at the key information (Entities, Attributes and the relationships) to generate the code I need.

See also: mogenerator.

Double Core Data Accessors by Omitting @NSManaged

$
0
0

Trevor Squires:

If our implementation is not exposed to Objective-C, then Core Data will not find it at runtime, which means that, yes, Core Data will dynamically generate the accessor implementation for us.

[…]

This is why I now consider Swift to be the most satisfying language for using Core Data. The fact that (more expressive) types can’t be represented in Objective-C is a benefit, not a limitation.

Swift NSManagedObject subclasses can provide Swift-only accessors which happily coexist with Core Data’s dynamically-generated ones, and that feels like the best of both worlds.

Update (2016-06-07): Marc Charbonneau:

When you declare an @NSManaged var in your managed object subclass, normally it can be an Int, Bool, or Double. But not for Core Data primitive accessors! Primitive accessors (not to be confused with primitive types, I’m talking about methods that are a shorthand for primitiveValueForKey: … ) must be declared as an NSNumber. You don’t have to explicitly wrap your value in an NSNumber, you can still assign an Int or Double to your var and Swift will box it up for you. Not a big deal, but something to remember if you find your app crashing.

Core Data Book

$
0
0

Florian Kugler and Daniel Eggert:

With this book we try to shine a new light on a framework that has been around for a while:

  • We embrace Swift 2 with all its latest language features to write more elegant and more safe Core Data code.
  • We focus on demonstrating best practices and advanced techniques that you can immediately apply to a wide range of projects.
  • We explain how Core Data works behind the scenes. This will help you to make better choices when e.g. designing your data model, deciding on a concurrency model, or optimizing performance.

I liked the chapters that I read of the pre-release version and look forward to finishing it now.

Update (2015-12-15): Ole Begemann:

In the section on concurrency and syncing, they discuss tons of stuff you won’t find covered elsewhere in this much detail. […] For instance, they wrote an abstraction for the sync engine that allows them to replace the calls to CloudKit with another implementation that just logs the commands that should be sent to the server. What started as a workaround to allow readers to run the sample app without provisioning problems turned into something that can be used in testing.

Core Data Threading Demystified

$
0
0

Marcus Zarra (comments):

In the best way, we go back to having one PSC, but we’re going to use the new APIs in iOS 6. We’re going to add a private MOC that talks to that PSC. Then, we’re going to add our main context and define it as a main context, and we’re going to make that a child of that private MOC. Any data processing will be below the main MOC, so we will have three levels of contexts.

[…]

This design allows us to have asynchronous saves, which is extremely important. It allows us to save and to consume or process data without blocking the UI. A user can happily scroll through our application, look at data, play with it, and we’re not telling them that they have to wait for us.

[…]

We have an extra level of indirection between the PSC and the main MOC, so we will get a little bit of slowness there. When I say little bit, I mean if I build up a test case it does thousands upon thousands of iterations, I will find a 1-2% variance in the speed.

[…]

You can use notifications to force one child to consume updates from the other child, but don’t do this. It’s just a bad idea.

Pragmatic Core Data

$
0
0

Florian Kugler:

Now to answer the ultimate question, how do I get best performance with Core Data? Is the question that I can un-answer in the abstract. I think that your best bet is to look at the architecture, to understand this architecture, to really see how do these different layers work. How are their performance characteristics of these layers and then reason about your app’s behavior with this background knowledge. When you do that you can make the right choice for your specific project.

[…]

The advantages of the [nested contexts] set up are that if you save stuff from the main context, for example, the scenario I mentioned before, you copy in tons of data into your app, just copy paste and then you save. Now the save doesn’t block the main thread any more. Because the save of your UI context, only pushes all this stuff down into this private context that’s below. The private context can save this later. It’s one of the major advantages, and one of the major reasons nested contexts were introduced with iOS 5, where there’s iCloud syncing stuff.

[…]

Another disadvantage is that saving a child context pushes all changes down into the parent context. So before I said when you merge change, merge save notifications, Core Data can discard stuff because it knows it is not of interest to the other context. Now, with nested context, Core Data has to channel all this data down to the store, so it has to push all of this in. So if you insert 10,000 objects in the child context, Core Data has to instantiate 10,000 objects in the parent context, even if you don’t care about them there.

[…]

Another disadvantage is that you have no merge policies. When you work with nested context, you save the child context and all the changes are pushed down into the parent context with brute force. There is no consideration about conflict resolution, this is just a brute force push down into the previous context. It just overrides. Another pretty esoteric issue is that once you work with nested contexts you have to be aware there are weird things going on with temporary and permanent object IDs, and you can run into weird situations where you can break stuff like the uniquing guarantees that Core Data usually has.


Core Data Join Table Records Not Deleted in Ordered Relationship

$
0
0

Tonester:

I’m having trouble with a core data many-to-many relationship where both side’s delete rules are set to Nullify. I’m finding when I inspect the SQL database there are records left in the join table that should be deleted.

The two tables represent Playlists and Tracks. Playlist deletes don’t cascade to delete each track automatically because each track can be in multiple playlists.

Tonester:

I’ve noticed if you delete the relationship i.e. using removePlaylistTracksObject:, then save, then delete the playlist and track, then save, it works. I would expect the relationship record to be removed when deleting either the playlist or track and a single save. Also if the playlist to tracks is not ordered it works fine.

Marcus Zarra:

Thanks for the test case, that is an actual issue in Core Data. There is nothing in there that you are doing incorrectly. You really need to file a radar on this and I will file one as well.

In the interim you can either stop using ordered relationships (they are a bastardization anyway) or do the double delete.

Previously: Core Data Bugs.

Update (2016-02-25): James O’Leary:

Every year for (x) years I think “I should get rid of my ordering hack”, do research, and find CD’s is still broken :(

UTF-8 String in Swift 5

$
0
0

Michael Ilseman:

Switching to UTF-8 fulfills one of String’s long-term goals to enable high-performance processing, which is the most passionate request from performance-sensitive developers. It also lays the groundwork for providing even more performant APIs in the future. String’s preferred encoding is baked into Swift’s ABI for performance, so it was imperative that this switch happen in time for ABI stability in Swift 5.

[…]

Swift 5, like Rust, performs encoding validation once on creation, when it is far more efficient to do so. NSStrings, which are lazily bridged (zero-copy) into Swift and use UTF-16, may contain invalid content (i.e. isolated surrogates). As in Swift 4.2, these are lazily validated when read from.

This sounds great, as I’ve run into problems in Objective-C where strings that are not valid Unicode would cause strange failures a layer or two below my code. I don’t see it documented what happens when validation fails, but my guess from the code is that it repairs the string using replacement characters. That makes sense given the cases I’ve seen. Set one bad attribute on a managed object, and the entire context fails to save. If validation were eager, maybe I could do better at the point of creation than replacement characters (assuming I’m even creating the strings myself). But, this much later, I don’t think there’s much to be done. It’s not worth risking data loss for the common case where the developer hasn’t anticipated this happening and written code to fix the strings.

As mentioned above, Swift 5 switches from two native storage representations to one. This allows for better analyses and more aggressive optimizations with fewer potential code-size or compilation time costs.

For example, inlining is a compiler optimization that can improve run-time performance at a potential cost to code size. In Swift 4.2, most string methods contained a pair of implementations, one for each storage representation. No matter what form a 4.2 string was in, an entire portion of potentially-inlined code wouldn’t even be run; this increases the cost and diminishes the benefits of inlining. Furthermore, the greatest benefits of inlining come from follow-on analyses and optimizations specific to one call-site, which are exponentially more difficult to perform on a dual representation. Swift 5’s unified storage representation is far more amenable to inlining and follow-on optimizations.

Michael Ilseman:

String remembers performance-relevant information about its contents through the use of performance flags.

For example, a String that is known to be all-ASCII has a trivial UTF8View, UTF16View, and UnicodeScalarView. Also, mapping offsets between the two code unit views is trivial, so there is no need for any bookkeeping as part of Cocoa interop.

Previously: String’s ABI and UTF-8.

@autoreleasepool Uses in 2019 Swift

$
0
0

Bruno Rocha:

To put it short, autoreleasepool is still useful in iOS/Swift development as there are still legacy Obj-C classes in UIKit and Foundation that call autorelease, but you likely don’t need to worry about it when dealing with Swift classes due to ARC’s optimizations.

Presumably, pure Swift objects can also be autoreleased when manipulated by Objective-C code. I still find autoreleasepool to be useful, both to reduce peak memory use and to ensure that resources associated with objects will be cleaned up at a particular time.

One pain point has been that XCTestCase doesn’t seem to use pools around its setUp() and tearDown() methods. This led to log messages from Core Data complaining that the SQLite database had been deleted out from under it when the test was over. An autoreleased controller had been retaining the persistent store coordinator.

I ended up making a subclass of XCTestCase with its own lifecycle methods that run inside autorelease pools and are allowed to throw errors.

WWDC 2019 Links

$
0
0

Syncing Core Data With CloudKit and NSPersistentCloudKitContainer

$
0
0

WWDC Session 202:

CloudKit offers powerful, cloud-syncing technology while Core Data provides extensive data modeling and persistence APIs. Learn about combining these complementary technologies to easily build cloud-backed applications. See how new Core Data APIs make it easy to manage the flow of data through your application, as well as in and out of CloudKit. Join us to learn more about combining these frameworks to provide a great experience across all your customers’ devices.

See also:

This is great to see, although for all the specific use cases I have in mind it would likely be more appropriate to use CloudKit directly. NSPersistentCloudKitContainer seems too automatic/opaque. (I say this before the session has taken place, though.)

Hunter Hillegas:

It’s a whole new managed approach where Core Data owns the CloudKit container and handles it. No clue how well it works.

Scott Perry:

Yup, Core Data CloudKit implements to-many relationships using CRDTs!

Drew McCormack:

Looking at the Core Data + CloudKit sample code, I have a feeling it might be a case of “fool me twice”. The fact that there is no global identifier for objects means you end up with a lot of messy deduplication code. Even a real basic app like the sample will scare many away.

Malcolm Hall:

You can get the global identifier using recordForManagedObjectID: it is stored in a meta data table, see attached screenshot:

Drew McCormack:

Yeah, I figured they had an id internally. My point is the user doesn’t seem to be able to pick one. Eg. merging tags is trivial if you can choose your own global id.

Malcolm Hall:

Oh so in the sample the deduplicate method is finding all tags with the same name, selecting one, and then setting all posts that are using any of the duplicates to the single tag. That’s pretty nasty.

Malcolm Hall:

So CloudKit Core Data Sync doesn’t merge in remote changes before syncing up the modified local record, and sends whole record not just changed fields, causing it to overwrite whatever changes another device made that was not yet received, seems like a dealbreaker.

Previously:

Update (2019-06-04): Malcolm Hall:

sadly Core Data CloudKit isn’t using CKReference for related records, just using a string field, thus losing integrity. I was really hoping they would make the public the CKReferenceActionValidate that Notes uses for e.g. the one-to-many folder notes relation.

Viewing all 217 articles
Browse latest View live