Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I just hope people can differentiate between Core Data and iCloud from both your comment and the article.Core Data isn't broken. It might be somewhat magical, but it's not broken.


I think there's a good argument for it being broken:

1) Core Data objects are not NSObject objects. You can't treat them remotely like normal objects: https://developer.apple.com/library/mac/documentation/Cocoa/...

2) Core Data requires making your model mutable, and spreading dependencies on Core Data's abnormal objects throughout your entire code base.

3) Since the abnormal objects are spread throughout your code, and they're tied to non-thread-safe NSManagedObjectContexts, concurrency becomes rather difficult. You have to deal with multiple managed object contexts becoming out-of-sync across threads. Most people just give up and perform expensive operations like -save on the main thread.

4) Core Data merges the concepts of your on-disk model with your in-memory model, despite the fact that the two problem domains have very different requirements in terms of API design, data longevity, relational design, etc. This leads to code that is neither a clean in-memory model, nor a clean on-disk model.

5) Since Core Data objects are abnormal objects, one must produce a considerable amount of boilerplate just to define new model objects. What time you save upfront using a GUI to design your original model, you spend 10-fold in maintaining the code to support it, and in being handicapped by the contraints Core Data places on your code.

6) NSPredicate is awful. It's a brain-dead query language that often make it impossible to cleanly normalize your data store. Aggregate operations are expensive and often require O(n) cost, the query language is poorly documented and poorly specified.

Core Data is a very poorly fit abstraction, but it probably works well enough for simple use-cases. Once you move into concurrency, complex/large models, aggregate operations/projections across your data, or have to deal with it failing, it falls over.

After using it myself for a large project and struggling with all of these issues (and more), and watching another team do the same on their own project, I'd never make use of it again. SQL (via sqlite) is a far better abstraction for managing on-disk data, especially when doing so in a highly concurrent application where one can rely on SQLite's transaction support.


1) How is this a problem?

2) I don't get this. Your model is tied to a context manager, even if they are mutable, you don't need to merge context throughout your base unless you want to.

3) They are not thread safe, the same way UIView isn't thread safe. Why would multiple managed context become out of sync unless you allow it? It's not difficult to deal with. Create a context in the queue you are in. Merge it when you're done.

4) You can use Core Data without persistent store and make it fully in memory and everything will work fine. You can even separate your memory context with multiple context managers. Separating your creates and your deletes and etc.

5) Fud. Write a wrapper, use existing wrappers.

6) Agree.

I am actually kinda curious what problems you've gotten into recently. I've seen Core Data be improved ever since I started using it in 4. I wish it had Cocoa bindings on iOS... but ah well. I've never had any concerns here.

I don't use it for complex stuff. Ironically I didn't use it for a graph though I was told it would be a perfect fit, i wasn't really sure how to traverse without pulling everything into memory. So ended up just using NSObjects and keyedarchiver. But I would be curious to see if someone more familiar with Core Data would have solved it with CD.


> 1) How is this a problem?

I touched on this in a peer comment, but it ties your hands in terms of doing rather normal things that would make for a better model API.

> 2) I don't get this. Your model is tied to a context manager, even if they are mutable, you don't need to merge context throughout your base unless you want to.

Using an immutable model makes concurrency far, far easier (among other things).

> 3) They are not thread safe, the same way UIView isn't thread safe. Why would multiple managed context become out of sync unless you allow it? It's not difficult to deal with. Create a context in the queue you are in. Merge it when you're done.

Like I said in reply to your other comment -- The difference is that the 'model' is what binds all of your code together. The constraints of Core Data therefor introduce tightly bound constraints on all your code.

> 4) You can use Core Data without persistent store and make it fully in memory and everything will work fine. You can even separate your memory context with multiple context managers. Separating your creates and your deletes and etc.

I think you're confusing what I mean by in-memory model and on-disk model.

The way one defines and represents on-disk storage is very different than in-memory storage: the data is persistent, it must remain accessible over time, the model must be versioned, and changes to the actual model definition must be applied as migrations between versions.

In-memory models, however, live only for the lifetime of a particular run of that application, may be modified freely, require no versioning, and require no migrations other than code refactoring.

By tightly binding these things together, Core Data creates the worst of both worlds: all the complexity and downsides of on-disk models with almost none of the flexibility and simplicity of in-memory models.

> 5) Fud. Write a wrapper, use existing wrappers.

That involves quite a bit more work than defining a simple class. Tools such as mogenerator are big, complicated, and a hassle. The point of Core Data is to save effort, but it generates more work and complexity.

> 6) Agree.

Well, at least we agree about something :)


Adding on to your #3, concurrency became MUCH, MUCH easier in iOS 5. Core Data gained the concept of a background/main thread context and the two methods -performBlock: and -performBlockAndWait:. See: https://developer.apple.com/library/mac/ipad/#documentation/... and http://www.cocoanetics.com/2012/07/multi-context-coredata/


This requires performing all mutation on dedicated code paths. If you require non-asynchronous completion, you have to use the 'wait' variant, but this introduces deadlock risk between threads.

This in turn litters your code with Core Data isms, and means that one can not simply make use of their model as a standard in-memory model.

Compare to SQLite, where one can simply open and commit a transaction synchronously on any thread.


Litters the code with Core Data ism? The same your code is littered with UIVism, NSFoundationsm and etc?

And yes, you can still not use a persistent store manage context on multiple queues.

Please stop using the word thread and use the word queue :)


> Litters the code with Core Data ism? The same your code is littered with UIVism, NSFoundationsm and etc?

The difference is that the 'model' is what binds all of your code together. The constraints of Core Data therefor introduce tightly bound constraints on all your code.

> Please stop using the word thread and use the word queue :)

Why? Queues are M:N mapped to threads, so they are still threads. Additionally, not all work is always done on queues, especially when working with legacy APIs.


Bingo. Core Data concurrency pretty much works these days.


That's a pretty carefully thought out list of grievances.

What do you mean by 1), though? The link shows a list of methods you can't override on NSManagedObject, but they're things like -class and -isEqual:, which seems pretty reasonable for a system that needs to inspect and compare its objects.

Core Data does solve a few tough problems well. Faulting, uniquing, and cross-context change merging are probably the top three. Yes, it can be much simpler to just query SQLite, but I've never seen somebody do that and abstract away updating stale copies of objects.


> What do you mean by 1), though? The link shows a list of methods you can't override on NSManagedObject, but they're things like -class and -isEqual:, which seems pretty reasonable for a system that needs to inspect and compare its objects.

Well, keep scrolling :~)

Especially 'Custom Instance Variables' and 'Custom Accessor Methods' and 'Validation Methods'. I don't think it's controversial that defining derived instance variables, accessor methods, or other derived state on model classes is an unusual or unwarranted desire, yet doing so with Core Data requires considerably more effort and complexity than a simple model object.


I've subclassed NSManagedObject and added instance variables and custom accessors literally every time I've written Core Data code. It's usually not a problem -- yes, you do have to do a couple things to preserve the underlying behavior.

What problems have you had?


I've found the 'couple things' to introduce enough overhead, that when coupled with the other downsides, Core Data hasn't saved me time, reduced LoC, provided any performance advantages, or improved code quality.


> Core Data objects are not NSObject objects.

Well, they are; they inherit NSManagedObject, which descends from NSObject. It's true that model objects need to follow a bunch of conventions, but that's by design.

> Core Data merges the concepts of your on-disk model with your in-memory model

That's a feature. I rather like how it forces you into rethinking your design.

From your other points it sounds (mind you, sounds, I am not judging) like your app was the wrong fit for Core Data. It's not a replacement for a full-fledged SQL RDBMS and was never intended to be. Core Data works swell for its intended scope.


I don't know anything about Core Data so pardon my ignorance. How has Apple marketed Core Data? I'm asking because the issues you've mentioned are solved well by SQLite, but perhaps that's because Core Data wasn't designed to be used in anything but the simplest use cases? That tends to happen with solutions that are magical.


Core Data is essentially an ORM layer on top of SQLite.


Core Data does look pretty awful if you compare it to an arbitrarily awesome imaginary library.

All you're doing in this post is phrasing problems that are fundamental to data storage in core-data specific verbage, and calling them a grievance against Core Data. But they're not. There's no other magical solution that somebody could write that does it any better.

For example:

> Since the abnormal objects are spread throughout your code, and they're tied to non-thread-safe NSManagedObjectContexts, concurrency becomes rather difficult.

Concurrency is difficult independently of how you go about it!. The fact that concurrency continues to be hard is not Core Data's problem. The question is, is it easier or harder to use Core Data's primitives to achieve concurrency than it would be doing everything from scratch? I think it's easier. But Core Data against magic is not a fair comparison; a fair fight is between [hard problem with off-the shelf tool] against [hard problem without any tools].

Or this one:

> Since Core Data objects are abnormal objects, one must produce a considerable amount of boilerplate just to define new model objects.

Again, the choice is not between [boilerplate] and [no boilerplate]. As you've correctly pointed out, the mapping between on-disk and in-memory is a hard problem, and the solution will involve writing code that bridges the two worlds. The question is, is [boilerplate that's defined over 10 years of Cocoa convention] superior to [boilerplate that I invented from scratch to solve my problem]? I'm going to claim, 90+% of the time, that you want door A. Perhaps you really do want door B occasionally. But there is no door C with a boilerplate-free existence.

> After using it myself for a large project and struggling with all of these issues (and more), and watching another team do the same on their own project, I'd never make use of it again.

And as a person who has worked on probably over two dozen Core Data applications, I would not touch any codebase that had this philosophy with a ten-foot pole. Concurrency, boilerplate, memory/disk impedance mismatch are the same problems wherever you go. It is perfectly fine to say "I don't like using CD syntax to solve these problems" as a personal preference. But it is another thing entirely to say that CoreData is "broken" because one is either unable or unwilling to solve these same problems we solve every other day of the week in a slightly different syntax than one is used to, particularly when that syntax is generally accepted as a platform standard.

To use an analogy, it would be very poor form to try a Ruby project or two and conclude that ActiveRecord is terrible and that it "falls over" once you step outside "simple use-cases" and that you would never do another Ruby project unless you were emitting postgres queries by hand. There are not a lot of Ruby developers who would sign up to work on that project.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: