Multithreading with Core Data on iOS

This post is copied from http://cutecoder.org/programming/multithreading-core-data-ios/

A while ago I recommended not to multithread at all with Core Data. That was true during Snow Leopard’s days. But with the advent of context hierarchy and the pervasive use of blocks on Lion and iOS 5, multi-threading with Core Data becomes approachable.

As I was working on Resonate, I discovered a number of lessons on writing multithreaded applications on iOS. A lot of these lessons were discovered “the hard way” – through misguided attempts and many crashes. I’d thought I share this with you so that you don’t need to go through the same mistakes.

Even though I use the word “multithreading”, chances are you won’t need to deal with threads directly. Using operation queues is the way to go for most of your multiprocessing mechanisms. Simply package your algorithms into distinct units of work and then let NSOperationQueuemanage them for you. Don’t create NSThread instances directly unless you have a pretty damn good reason why.

Use UIManagedDocument for Core Data apps on iOS.

Really, when you’re writing iOS 5 applications that uses Core Data, you’ll want to use UIManagedDocument. At a bare minimum, use this class to manage your Core Data stack. That is, let core data manage your instances of NSManagedObjectContextNSPersistentStoreCoordinator, and other parts of the Core Data stack.

Even if you need to share your Core Data classes with your Mac app, you can still separate your entity classes that will work accross both platforms. If you think that UIManagedDocument isn’t good enough for your app, you’d better have a damn good reason why.

When you use UIManagedDocument, you’ll get a set of interrelated NSManagedObjectContext instances. Amain context that you use as per normal with your GUI objects and the root context, which is the main context’s parent that are used for asynchronously saving data to persistent storage. When dealing with object contexts created by UIManagedDocument you should not save them directly – you’ll bypass undo management and a lot of other behind-the-scenes stuff. UIManagedDocument will periodically save these for you in the correct order.

Use the managed object context hierarchy

From this building block, I go further to recommend a pattern for using the new context hierarchy. I discovered this works nicely on iOS when I was working on Resonate.

  • Use the root context for saving data obtained by network refreshes.
  • Use the main context for GUI components and others that needs to be in the main thread.
  • Create individual worker contexts as children of the main context for background data processing tasks.

Core data context use

Use the Root Context for Network Refreshes

Being a Twitter client, Resonate often need to ask Twitter for the latest tweets and other data. When Twitter returns and Resonate parsed the resulting JSON data, it then invokes the root context’s operation queue to store the parsed JSON data into managed objects.

You can use this pattern yourself. You run network operations asynchronously, parse the resulting data, and then when you’re ready to store it you call performBlock on the root context.

You can see the pattern in the sequence diagram below. Typically the user initiates the refresh from an action in the view controller. If you use ASIHTTPRequest for your network I/O, you can make it run asynchronously. When the request is complete, you pass the raw data into an operation queue for parsing (note that +[ASIHTTPRequest sharedQueue] is convenient for this). When the data is parsed, you make use of the root context’s private queue to update the data to your managed objects. Upon completion of the update, you pass the object IDs of the updated objects back to your view controller in the main thread. Please take care not to pass the actual managed object instances between operation queues as this will certainly cause problems.

Network Refresh Pattern

One caveat of this approach is that you need to separate network-sourced data with user-edited data. That is attributes that can be updated from the network should not be editable by the user. This is to prevent conflicts when UIManagedDocument tries to saves your contexts.

Use Multiple Child Contexts for Worker Queues

If you need to do some long-running data processing, you should run those in a background operation queue and not in the main thread. But really to make your app responsive, anything that may take longer than half a second should be taken off the main thread – especially important in iOS devices where the CPU is a lot slower than the one found in OS X machines.

Those background operations should use their own private NSManagedObjectContext instances. I also recommend that these contexts are set as children of the main context. Why? Because when the operation completes and the context is saved then the results are “pushed” into the main context. This also rescues the GUI from having to refresh its NSManagedObjectContext to get the updated objects. Since you create these contexts yourself, you are responsible for saving them – unlike the main and root contexts that are owned by UIManagedDocument.

How to use it? Refer to the interaction diagram below. Typically the view controller creates the worker operation class (which is an instance of NSOperation). As part of the worker’s initial setup regime, the view controller provides its context as the parent context for use by the worker object. Then when the worker starts it creates its own private NSManagedObjectContext instance and use that context as it’s scratchpad data store. Just before the worker completes, it saves the context to push its changes to the main thread’s context.

Core Data for Background Processing

Conclusion

You now know how to multi-thread effectively in Core Data applications. Although this article focuses on iOS, you should be able to apply the same principles to OS X. You have learned about:

  • Using UIManagedDocument for managing your Core Data stack
  • The new NSManagedObjectContext hierarchy (nested contexts)
  • How use each level in the context hierarchy for different operation types (network refresh, main/GUI thread, worker operation).
Advertisements

Multi-Context CoreData

This post is copied from http://www.cocoanetics.com/2012/07/multi-context-coredata/

When you start using CoreData for persisting your app data you start out with a single managed object context (MOC). This is how the templates in Xcode are set up if you put a checkmark next to “Use Core Data”.

Using CoreData in conjunction with NSFetchedResultsController greatly simplifies dealing with any sort of list of items which you would display in a table view.

There are two scenarios where you would want to branch out, that is, use multiple managed object contexts: 1) to simplify adding/editing new items and 2) to avoid blocking the UI. In this post I want to review the ways to set up your contexts to get you what you want.

Note: I am wrapping my head around this myself for the very first time. Please notify me via e-mail about errors that I might have made or where I am explaining something incorrectly.

First, let’s review the single-context setup. You need a persistent store coordinator (PSC) to manage talking to the database file on disk. So that this PSC knows how the database is structured you need a model. This model is merged from all model definitions contained in the project and tells CoreData about this DB structure. The PSC is set on the MOC via a property. The first rule to remember: A MOC with a PSC will write to disk if you call its saveContext.

Consider this diagram. Whenever you insert, update or delete an entity in this single MOC then the fetched results controller will be notified of these changes and update its table view contents. This is independent of the saving of the context. You can save as rarely or as often as you want. Apple’s template saves on each addition of an entity and also (curiously) in applicationWillTerminate.

This approach works well for most basic cases, but as I mentioned above there are two problems with it. The first one is related to adding a new entity. You probably want to reuse the same view controller for adding and editing an entity. So you might want to create a new entity even before presenting the VC for it to be filled in. This would cause the update notifications to trigger an update on the fetched results controller, i.e. an empty row would appear shortly before the modal view controller is fully presented for adding or editing.

The second problem would be apparent if the updates accrued before the saveContext are too extensive and the save operation would take longer than 1/60th of a second. Because in this case the user interface would be blocked until the save is done and you’d have a noticeable jump for example while scrolling.

Both problems can be solved by using multiple MOCs.

The “Traditional” Multi-Context Approach

Think of each MOC as being a temporary scratchpad of changes. Before iOS 5 you would listen for changes in other MOCs and merge in the changes from the notification into your main MOC. A typical setup would look like this flow chart:

You would create a temporary MOC for use on a background queue. So allow the changes there to also be persisted you would set the same PSC on the temporary MOC as in the main MOC. Marcus Zarra put it like this:

Although the NSPersistentStoreCoordinator is not thread safe either, the NSManagedObjectContext knows how to lock it properly when in use. Therefore, we can attach as many NSManagedObjectContext objects to a single NSPersistentStoreCoordinator as we want without fear of collision.

Calling saveContext on the background MOC will write the changes into the store file and also trigger a NSManagedObjectContextDidSaveNotification.

In code this would roughly look like this:

dispatch_async(_backgroundQueue, ^{
   // create context for background
   NSManagedObjectContext *tmpContext = [[NSManagedObjectContext alloc] init];
   tmpContext.persistentStoreCoordinator = _persistentStoreCoordinator;

   // something that takes long

   NSError *error;
   if (![tmpContext save:&error])
   {
      // handle error
   }
});

Creating a temporary MOC is very fast, so you don’t have to worry about frequently creating and releasing these temporary MOCs. The point is to set the persistentStoreCoordinator to the same one what we had on the mainMOC so that the writing can occur in the background, too.

I prefer this simplified setup of the CoreData stack:

- (void)_setupCoreDataStack
{
   // setup managed object model
   NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Database" withExtension:@"momd"];
   _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

   // setup persistent store coordinator
   NSURL *storeURL = [NSURL fileURLWithPath:[[NSString cachesPath] stringByAppendingPathComponent:@"Database.db"]];

   NSError *error = nil;
   _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_managedObjectModel];

   if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) 
   {
   	// handle error
   }

   // create MOC
   _managedObjectContext = [[NSManagedObjectContext alloc] init];
   [_managedObjectContext setPersistentStoreCoordinator:_persistentStoreCoordinator];

   // subscribe to change notifications
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_mocDidSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:nil];
}

Now please consider the notification handler which we set as target for whenever such a didSave notification arrives.

- (void)_mocDidSaveNotification:(NSNotification *)notification
{
   NSManagedObjectContext *savedContext = [notification object];

   // ignore change notifications for the main MOC
   if (_managedObjectContext == savedContext)
   {
      return;
   }

   if (_managedObjectContext.persistentStoreCoordinator != savedContext.persistentStoreCoordinator)
   {
      // that's another database
      return;
   }

   dispatch_sync(dispatch_get_main_queue(), ^{
      [_managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
   });
}

We want to avoid merging our own changes, hence the first if. Also if we have multiple CoreData DB in the same app we want to avoid trying to merge changes that are meant for another DB. I had this problem in one of my apps which is why I check the PSC. Finally we merge the changes via the provided mergeChangesFromContextDidSaveNotification: method. The notification has a dictionary of all the changes in its payload and this method knows how to integrate them into the MOC.

Passing Managed Objects Between Contexts

It is strictly forbidden to pass a managed object that you have gotten from one MOC to another. There is a simple method to sort of “mirror” a managed object via its ObjectID. This identifier is thread-safe and you can always retrieve it from one instance of an NSManagedObject and then call objectWithID: on the MOC you want to pass it to. The second MOC will then retrieve its own copy of the managed objects to work with.

NSManagedObjectID *userID = user.objectID;

// make a temporary MOC
dispatch_async(_backgroundQueue, ^{
   // create context for background
   NSManagedObjectContext *tmpContext = [[NSManagedObjectContext alloc] init];
   tmpContext.persistentStoreCoordinator = _persistentStoreCoordinator;

   // user for background
   TwitterUser *localUser = [tmpContext objectWithID:userID];

   // background work
});

The described approach is fully backwards-compatible all the way down to the first iOS version that introduced CoreData, iOS 3. If you are able to require iOS 5 as deployment target for your app then there is a more modern approach which we shall inspect next.

Parent/Child Contexts

iOS 5 introduced the ability for MOCs to have a parentContext. Calling saveContext pushes the changes from the child context to the parent without the need for resorting to the trick involving merging the contents from a dictionary describing the changes. At the same time Apple added the ability for MOCs to have their own dedicated queue for performing changes synchronously or asynchronously.

The queue concurrency type to use is specified in the new initWithConcurrencyType initializer on NSManagedObjectContext. Note that in this diagram I added multiple child MOCs that all have the same main queue MOC as parent.

Whenever a child MOC saves the parent learns about these changes and this causes the fetched results controllers to be informed about these changes as well. This does not yet persist the data however, since the background MOCs don’t know about the PSC. To get the data to disk you need an additional saveContext: on the main queue MOC.

The first necessary change for this approach is to change the main MOC concurrency type to NSMainQueueConcurrencyType. In the above mentioned _setupCoreDataStack the init line changes like shown below and the merge notification is no longer necessary.

_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:_persistentStoreCoordinator];

A lenghty background operation would look like this:

NSMangedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
temporaryContext.parentContext = mainMOC;

[temporaryContext performBlock:^{
   // do something that takes some time asynchronously using the temp context

   // push to parent
   NSError *error;
   if (![temporaryContext save:&error])
   {
      // handle error
   }

   // save parent to disk asynchronously
   [mainMOC performBlock:^{
      NSError *error;
      if (![mainMOC save:&error])
      {
         // handle error
      }
   }];
}];

Each MOC now needs to be used with performBlock: (async) or performBlockAndWait: (sync) to work with. This makes sure that the operations contained in the block are using the correct queue. In the above example the lengthy operation is performed on a background queue. Once this is done and the changes are pushed to the parent via saveContext then there is also an asynchronous performBlock for saving the mainMOC. This again is happening on the correct queue as enforced by performBlock.

Child MOCs don’t get updates from their parents automatically. You could reload them to get the updates but in most cases they are temporary anyway and thus we don’t need to bother. As long as the main queue MOC gets the changes so that fetched results controllers are updated and we get persistence on saving the main MOC.

The awesome simplification afforded by this approach is that you can create a temporary MOC (as child) for any view controller that has a Cancel and a Save button. If you pass a managed object for editing you transfer it (via objectID, see above) to the temp context. The user can update all elements of the managed object. If he presses Save then you save the temporary context. If he presses cancel you don’t have to do anything because the changes are discarded together with the temporary MOC.

Does your head spin by now? If not, then here’s the total apex of CoreData Multi-Context-ness.

Asynchronous Saving

CoreData guru Marcus Zarra has shown me the following approach which builds on the above Parent/Child method but adds an additional context exclusively for writing to disk. As alluded to earlier a lenghty write operation might block the main thread for a short time causing the UI to freeze. This smart approach uncouples the writing into its own private queue and keeps the UI smooth as button.

The setup for CoreData is also quite simple. We only need to move the persistentStoreCoordinator to our new private writer MOC and make the main MOC be a child of this.

// create writer MOC
_privateWriterContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_privateWriterContext setPersistentStoreCoordinator:_persistentStoreCoordinator];

// create main thread MOC
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
_managedObjectContext.parentContext = _privateWriterContext;

We now have to do 3 saves for every update: temporary MOC, main UI MOC and for writing it to disk. But just as easy as before we can stack the performBlocks. The user interface stays unblocked during the lengthy database operation (e.g. import of lots of records) as well as when this is written do disk.

Conclusion

iOS 5 greatly simplified dealing with CoreData on background queues and to get changes flowing from child MOCs to their respective parents. If you still have to support iOS 3/4 then these are still out of reach for you. But if you are starting a new project that has iOS 5 as minimum requirement you can immediately design it around the Marcus Zarra Turbo Approach as outlined above.

Zach Waldowski pointed out to me that using a private queue concurrency type for “editing view controllers” might be overkill. If you use NSContainmentConcurrencyType instead on the child view controllers context then you don’t need the performBlock wrapping. You’d still have to performBlock on the mainMOC for saving.

The confinement concurrency type is “the old way” of doing contexts, but that doesn’t mean it’s legacy. It simply ties the operations of the context to a self-managed threading model. Spinning up a private queue for every new view controller is wasteful, unnecessary, and slow. -performBlock: and -performBlockAndWait: don’t work with the confinement concurrency type for a reason, because neither blocks nor locking are necessary when you’re doing multiple contexts in the way that you are in the “editing” view controller setup.

NSManagedObjectContext knows how to save and merge intelligently, and because the main thread context is bound to the main thread, its merges are always performed safely. The editing view controller is bound to the main thread just like the main view controller; the only way it’s a separate operation is just in a UI sense, which is why it’s appropriate to use the confinement concurrency type here. The editing context isn’t conceptually a “new” thing, it’s just deferring the change until later, while still allowing you to discard the changes entirely.

So it really boils down to your personal preference: private queue with performBlock or confinement concurrency without. Personally have a tendency to prefer private queues because of the warm fuzzy and safe feeling I get from using them.

Problems with nested contexts

This post is copied from http://wbyoung.tumblr.com/post/27851725562/core-data-growing-pains

When Mac OS X 10.7 and iOS 5 were released, I was so excited about the new features in Core Data. The additions of explicit concurrency types, nested contexts, and iCloud syncing promised to make developing with Core Data even more delightful. After evaluating these features, our team decided that we were going to use them in the next major release of one of our apps. Unfortunately (as is sometimes the case), some of these features aren’t quite ready for prime time.

Today I’m going to discuss nested context support in Core Data and various issues that exist with them. Some of these issues are minor bugs. Others may be considered functionally correct by the Core Data team, but result in unexpected behavior. Regardless, they add up to nested contexts being a feature you should avoid completely (as of this writing).

Background

So what are nested contexts anyway? To avoid a very lengthy explanation, I’m going to start by assuming that you understand the Core Data stack. Nested contexts allow you to set up a managed object context so that it accesses data from a parent context instead of from a persistent store. If you request an object from a managed object context that has a parent context, Core Data will first look in the parent. If the parent context has that object in memory, you’ll get a new managed object just like that one. So if there are changes in the parent, you’ll get the changed version of the object. If the object doesn’t exist in that context, it will keep going up through parent contexts until it finally fetches the data from the persistent store. Basically, retrieving data goes all the way up through all ancestor contexts. Saving, on the other hand, doesn’t traverse up through parent contexts — it only saves one level up. All of this is pretty well explained elsewhere, so I’m going to leave it at that.

Issues

Throughout the last 9 months, we’ve been using nested contexts in an attempt to simplify and improve some of the data processing that we do in our personal finance application, Koku. It feels like at every turn we’ve been finding issues in Core Data where nested contexts are to blame. Many of these issues are a bit difficult to explain because there is a lot of setup required to reproduce them. With that being said, here is what we’ve found so far:

Child contexts block ancestors

This is one of the most fundamental problems with nested contexts. When I was first told about this through some friends in Chicago, I didn’t believe it. Basically, when you execute a fetch request in a child context, it blocks the parent context while performing the fetch. What does this mean? Well it means that you can’t really use nested contexts to solve a lot of concurrency issues.

Here’s an example: you have a bunch of objects in your database that need to be fetched and have time-intensive code executed on them. The following code looks like it would solve your problems:

NSManagedObjectContext *asyncContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[asyncContext setParentContext:mainContext];
[asyncContext performBlock:^{
    // create fetch request, execute, and do work
}];

But executing that fetch request blocks the main context. Assuming that main context is running on the main thread, then this also makes your application stop responding.

I’ve commonly heard people using this setup for importing from some type of service. And this is where things start to get bad. Let’s say you’re importing a bunch of JSON objects and you need to check if each already exists in Core Data based on an identifier. You write code that loops and checks for an object in Core Data with that identifier, then creates a new object from the JSON data if it doesn’t exist (yes, that could be optimized). It may look like everything is going fine because your UI is still responsive through most of that import (especially if you’re reading from a stream since there will be a delay between each ID check). The truth is, though, that every time you check for an object with an identifier, you’re blocking your UI. It may only be for a fraction of a second, but no one is expecting this.

Now this in itself is not really a large problem. Once you understand it, it’s just another part of the framework that you work with/around. The real problem is that nothing in the documentation indicates that this will happen. In fact, the release notes read:

This pattern has a number of usage scenarios, including:

  • Performing background operations on a second thread or queue.
  • Managing discardable edits, such as in an inspector window or view.

Right there in the release notes, Apple is telling us to use nested contexts to do work in the background. But you absolutely should not use them for that. They will block the parent.

radar://10581934

Making changes into a parent context can be slow

Sometimes the cost of making changes in a child context is outrageous. Simply changing a boolean value on a bunch of objects can be prohibitively slow. It seems that Core Data tries to do something while processing pending changes on the child context. A reasonable assumption is that Core Data is trying to negotiate changes between the two contexts. All we’ve been able to determine is that there’s a lot going on with dictionary lookup that can hang the app. Everything takes far longer than if you were doing the same thing in a context that was tied directly to a persistent store coordinator.

Fetch results are wrong in a child context

It’s possible that fetch requests will not return the right results. I cannot even begin to understand how nested contexts got released when something this fundamental is broken. (Ok, so it’s broken in a very specific way, but still.)

Here’s how you can get Core Data to return the wrong results: set up a nested context relationship just like they describe for UIManagedDocument. For those who are unfamiliar, this involves an asynchronous context that is connected to the persistent store coordinator. The main queue context sets its parent to be this asynchronous context.

With the contexts set up, create a new object. Let’s imagine this object represents a blog and its variable name is awesomeBlog.  Add a couple of articles to that blog. Now if you were to set up a fetch request for all of the articles with a predicate of [NSPredicate predicateWithFormat:@"blog = %@", awesomeBlog], you’d get back the right results. But if you save the main context and then the async context (so the data is actually persisted to the disk) and try executing that fetch request, you would get no results. And it doesn’t matter if you set up the fetch request before or after you persist the data. You’ll never get the right results. Without nested contexts, this works just fine!

There is a workaround for this issue. You can simply obtain a permanent ID for the object when you create it. But there is a catch. The async context (at least in the case of UIManagedDocument) exists so that you can write data asynchronously. By getting a permanent ID for each object you create, you’ve made it so that you’re doing synchronous writes more frequently.

Oh, and as an added bonus, everyone who uses UIManagedDocument will experience this bug.

This has been reported as fixed for an upcoming release of iOS (which means the same should be true for Mac OS X).

radar://11891033 fixed in an upcoming release

Cannot access relationship in a child context for unsaved objects

This is pretty similar to the issue above in that it deals with relationships of objects that have been created. The difference is in the context setup and that it doesn’t really involve saving.

Here’s what can happen: let’s say you’re working in a managed object context called mainContext. It doesn’t need to have a parent context; it can be hooked up directly to the persistent store. Insert a new object into that context. Let’s call it a blog again. Add a few articles to that blog. Now, create a new managed object context and set it’s parent to mainContext. We’ll call this new context editing context. It’s another one of those common workflows that Apple documented in the release notes for nested contexts — discardable edits. But here’s what happens: when you access your blog ineditingContext, it has no articles.

The workaround for this is the same as the last one. Just obtain the permanent ID of the object beforehand. This has also been reported as fixed for Mac OS X 10.8 Mountain Lion (which means the same should be true for iOS 6).

radar://10209854 fixed in an upcoming release

Sorting is not honored when there are changes in a parent context

Sort descriptors are important, right? Well they don’t seem to always matter when you’re using nested contexts. If you have changes in a parent context and you execute a fetch request in the child, sorting does not work. Mix that with some of the above issues and you may get out of order, incomplete results. Yikes!

NSFetchedResultsController deadlocks

You never want your application to deadlock. With NSFetchedResultsController and nested contexts, it’s pretty easy to do. Using the sameUIManagedDocument setup described above, executing fetch requests in the private queue context while using NSFetchedResultsControllerwith the main queue context will likely deadlock. If you start both at about the same time it happens with almost 100% consistency.NSFetchedResultsController is probably acquiring a lock that it shouldn’t be. This has been reported as fixed for an upcoming release of iOS.

radar://11861499 fixed in an upcoming release

Crash after obtaining permanent IDs

A few of the issues above could be worked around by getting the permanent ID of an object. This can actually lead to a crash in certain circumstances, though. Again using the UIManagedDocument setup, create a new main queue context, editingContext, off of the existing main queue context,mainContext. Create a new object in editingContext. Save editingContext. Obtain a permanent ID for the same object in the mainContext. Core Data will eventually crash when cleaning up resources no longer in use.

radar://10480982 fixed in an upcoming release

Wrapping Up

If you made it through all of those, you’ve probably come to the conclusion that nested contexts are currently something to avoid. If not, the bullet points alone may have been enough to cause some unease. And these are only the issues that we’ve experienced. I wouldn’t be surprised if there are more. In discussions with peers, I’ve found that there are many people who are discovering some of these same issues and finding ways to work around them individually. I hope this list helps you make an informed decision about using nested contexts before you go down the same road we did. Also, please consider filing duplicate radars for those that are listed above. If you have anything to add to this list, please reach out to me on twitter or send me an email.

Thinking back over the lifetime of Core Data, it’s pretty unfortunate to see so many problems with the recently introduced features. I remember back when Core Data was released that SenTestingKit was just making its way into Xcode. At some point, Apple used Core Data as a poster child for unit testing. They claimed they were able to tune and enhance the performance in Core Data, making it screaming fast because of the comprehensive tests that they wrote. Whether this was marketing or not, the framework has been pretty solid throughout the years. The issues that have cropped up with nested contexts (and don’t even get me started on iCloud) feel like huge oversights and problems that fall nicely into the comprehensive test coverage category.

With all that being said, nested contexts are such a wonderful idea that could simplify architecture issues that so many developers using Core Data face. I look forward to the day that they work flawlessly and we get to start using them to make the next generation of data backed applications.

Update 2012.08.08: Updated information on radars. Update 2012.09.16: Updated information on radars.

几个提高 iOS 开发效率的开源类库及工具

以下几个提高 iOS 开发效率的开源类库及工具,转自 CocoaChina 会员 “花太香齐” 的博客,有修改。希望能对您的开发工作有所帮助。

几个常用的开源类库及下载地址:1.json json编码解码
2.GTMBase64 base64编码解码
3.TouchXML xml解析
4.SFHFKeychainUtils 安全保存用户密码到keychain中
5.MBProgressHUD 很棒的一个加载等待特效框架
6.ASIHTTPRequest http等相关协议封装
7.EGORefreshTableHeaderView 下拉刷新代码
8.AsyncImageView 异步加载图片并缓存代码
9.类似setting的竖立也分栏程序

AppStore软件排名相关,工欲善其事,必先利其器。

1.下载排名相关:appannie 和 http://developer.cocoachina.com/brand
2.用户行为分析:flurry
3.majicrank-各国排名查询工具
4.AppViz-App销售统计软件
5.PodViz-用户评论等查看工具
6.appfigures-报表统计分析工具

12个2012年度最佳移动网页设计字体

VentureBeat评选出了2012年最好看的12种移动网页字体,如果你正在寻找好看又免费的英文字体,不妨来看看。

1. Noticia:最适合平板电脑杂志阅读

Noticia字体系列属衬线字体,易读性较高, 用作新闻杂志封面字体很容易引起一些年过25岁的人的阅读兴趣。同时,Noticia也打破了以往圆形字符(比如O、P等)内部形状规则,为大号字体的圆形符号内部增加了点趣味。

noticia

2. Bariol:最好的新型圆形字体

目前,圆形字体是网页和应用字体设计的一个趋势。Bariol能让你的应用设计语言更加丰富,在它的官网上下载需要收费,但你可以点击左下角登录Twitter或Facebook免费下载。

bariol

3. Poly:最佳网页衬线字体

Poly字体优雅,其适中的x字母高度和小写字体高度非常适合小号字体,特别是手机网页。

poly

4. Quando:仅次于Poly的网页衬线字体

Quando字体源于二战时期意大利海报,字体衬线曲线比较随意,能够让文章标题更有吸引力,且适用于移动设备上运行的文本;不过它没有加粗和斜体。

quando

5. Valentina:花式字体的最佳选择

如果你对网页兼容性的要求不是太高,同时也想在字体上玩点新花样,可以试试Valentina。不管是大小写字体交替或是漂亮的花式字体,Valentina都能满足你的要求。

valentina

6. Erler Dingbats:最佳装饰符号

提供800多个字符选择包括图标、地图元素、表格以及logo等,帮你打造甜美UI。

dingbats

7. Gleegoo:最佳瘦长型字体

虽欠缺优雅,但其苗条的板型衬线和精致的字形为Gleegoo加分不少。

gleegoo

8. Sofia:最佳新式书写字体

Sofia字体带有复古感,适用于文章标题和标志性文字。

sofia

9. Oregano:最佳手写体字体

如果想让你的网站或应用界面带点当年广告黄金时代的感觉,可以试试这个字体。总共就常规和斜体两种形式,随意却不会沦为卡通风格。

oregano

10. Londrina:最佳海报式标题字体

这种字体设计是基于圣保罗的海报艺术,能配合阴影、轮廓和素描字体形成不同效果,尤其适合字母全部大写的情况。

londrina

11. Montserrat:最佳复古艺术字体

古董是新型的现代艺术,如今网络上也很流行复古字体。Montserrat的字体灵感来自布宜诺斯艾利斯的历史街区的各种标识牌,不论是常规还是加粗体都能给你的网页带来浓浓的复古感。

montserrat

12. Source Code:最佳网页代码字体

越来越多的网页允许访问用户查看源代码,因此代码字体的阅读体验也是网页设计师关注的一个方面。最重要的是,这种等宽字符形式下,数字1和大小写的字母I能够一眼辨认出来。

sourcecode

见仁见智,每个人对相同事物的感觉是不一样的。以上只是VB一家的评选结果,相信各位网页设计师对字体也有自己的见解,欢迎分享。

 

 

为设计iOS应用寻找灵感的12个去处

专注于分享UI界面的细节,按照设计元素进行分类: pttrns PatternsofDesign MobileUIPatterns 专注iPhone的UI分享: TapFancy TappGala WellPlacedPixels lovelyui BuildingiPhoneApps 专注于iPad UI分享: LandingPad Sty

专注于分享UI界面的细节,按照设计元素进行分类(如需翻墙,请自备梯子):

pttrns

专注iPhone的UI分享:

TapFancy

专注于iPad UI分享:

LandingPad

此网站有一个iPad客户端,设计很精美:http://itunes.apple.com/us/app/stylapps/id444930066

专注于App网站设计的分享:AppSites

最后推荐一个包括了图标、界面、App网站和设计资源的整合型:iosinspires

 

来源:http://www.cocoachina.com/applenews/devnews/2013/0131/5637.html

Two Powerful Tools for Beginning Your Resume

This post is copied from http://resumewritinginfo.net/two-powerful-tools-for-beginning-your-resume/

In the first 30 seconds, your résumé has to (almost literally) grab the reader by the throat, jump on his chest, and scream HIRE ME! (OK, I’m exaggerating for effect, but that’s to illustrate the importance of getting the reader’s attention.) How to do that is to show the reader right away that you understand the employer’s business problem that caused the opening, and that you are THE solution to that problem.

How do you do that? One tactic is by using an objective, such as: “I am seeking a full time position with [name the company you’re applying to] as a [name the position you want]. Having succeeded in [your experience #1, as shown in the ad], [your experience #2, as taken from the ad], and [experience #3, as taken from the ad], I am confident that I will provide you immediate value. I will help your company achieve its objectives.”

If you use an objective, it must be all about what you will do for the employer, in the same way that your entire résumé has to answer the employer’s “What’s in it for me?” question. From your first words through your last, that objective must convey the message that “You’re looking for A, B and C skills and I do them. And what’s more, I do a great job at them.”

The truth of it is, your résumé only gets about 15 seconds of that reader’s time, if you’re lucky. In a perfect world, every résumé would receive the attention it deserves and every deserving jobseeker would… But you get the idea. It’s not a perfect world. And in reality, the reader will make a judgment about your résumé by the time s/he’s only about a third of the way down.

A better tactic than the objective is to write your Unique Selling Proposition, or USP,in the form of a strongly worded Summary. That Summary, when properly written, should demonstrate why you should be chosen out of the 400 or so applicants who have answered the advertisement. Such a USP might look like this: “Analytical, organized Financial Analyst recognized for achievements in administrating new loan funds, implementation of loan closing, and evaluating borrowers’ ability to repay mortgages. Strong problem-solving skills. Analyzed other branches’ loans to ensure 95% loan confidence rate.”

Now the reader has a clear picture of who this applicant is and what s/he can do for the company. This applicant has made a strong case for him/herself, and what’s more, s/he demonstrates how unique s/he is. This summary shows accomplishments, skills, and abilities in a much better way than the objective did, because each statement is a quantifiable. The summary also has an advantage over the objective in that most hiring managers and recruiters prefer a strong summary because objectives tend to be about what the applicant wants, rather than what the applicant has to offer the company.

However, regardless which you use, objective or summary, keep in mind the employer’s question: “What’s in it for me?”