directadmin安装成功后2222访问不了(All)

这是官方的处理方法:

If you are unable to access your server via http://1.2.3.4:2222, then 1 of 3 things is likely happening:

1. DirectAdmin might not be running or(第一种可能,就是DA没有正常安装)

2. You have a firewall blocking port 2222.(第二就是防火)

Number 2 is easy to check by simply running (only on redhat systems):
/sbin/service iptables stop
/sbin/chkconfig iptables off

Then test directadmin again.

If that didn't fix it, then you'd need to check your /var/log/directadmin/error.log to check for any errors as to why it isn't starting:
tail /var/log/directadmin/error.log (如果 试了上在两个方法还是不行,可查看错误列表)

Common problems are:
3. Incorrect ethernet_dev set in the /usr/local/directadmin/conf/directadmin.conf file. guide

4. Invalid license, either due to wrong uid/lid, IP, or date.  Try: Updating your DirectAdmin License manually

5. Your IP is blacklisted in /usr/local/directadmin/data/admin/ip_blacklist.  This is controlled by the "brute force login detection" in Admin Settings.  Use a setting no lower than 10, since even loading the login page counts as 1 failed attempt.

6. Binaries for a different operating system. Related

You can always try running DirectAdmin by hand (if it's not already running) to see what the problem is.
cd /usr/local/directadmin
./directadmin b200

to start it in the terminal with debug level 200.  Use Ctrl-C to stop.

7. If DirectAdmin is running, is bound to port 2222, but doesn't respond on "127.0.0.1", but does respond on "::1", then it's an IPv6 issue.  This guide would be related.

Directadmin如何更换授权IP

本次错误为:
The ip of this machine () does not match the ip in the license file
解决方法:

If you get the message:
The ip of this machine () does not match the ip in the license file

when trying to start DirectAdmin (or (1.2.3.4) instead of ()) then the ethernet_dev setting in your directadmin.conf files isn't setup correctly.

Type:
/sbin/ifconfig

to see which device name your IP is on.  Common devices names/formats are: eth0, eth0:1, eth1, venet0:0, etc..  Note that you can specify the sub-device name to get different IPs.

Once you know the device name, edit /usr/local/directadmin/conf/directadmin.conf
Change (or add) the setting:
ethernet_dev=eth0

再用下面的命令重启directadmin

# /etc/init.d/directadmin restart

django 安装 directadmin安装

django-admin.py startproject hello
python manage.py runserver p.smtch.com:8000

gunicorn hello.wsgi:application –bind p.smtch.com:8001


yum groupinstall -y development

yum groupinstall -y 'development tools'

curl https://raw.github.com/pypa/pip/master/contrib/get-pip.py | python
或者: wget https://raw.github.com/pypa/pip/master/contrib/get-pip.py
$ python get-pip.py

pip install virtualenv
yum install -y zlib-dev openssl-devel sqlite-devel bzip2-devel


Create and activate an environment for your application

I like to keep all my web apps in the /webapps/ directory. If you prefer /var/www/ or something else, use that instead.

$ cd /webapps/
$ virtualenv hello_django(创建一个环境)

New python executable in hello_django/bin/python
Installing distribute..............done.
Installing pip.....................done.

$ cd hello_django
$ source bin/activate
(hello_django) $ 

接着安装django

Your environment is now activated and you can proceed to install Django inside it.

(hello_django) $ pip install django

Downloading/unpacking django
(...)
Installing collected packages: django
(...)
Successfully installed django
Cleaning up...


安装完成,运行project:

django-admin.py startproject hello

接着可试运行development server:



(hello_django) $ cd hello
(hello_django) $ python manage.py runserver example.com:8000
Validating models...

0 errors found
June 09, 2013 - 06:12:00
Django version 1.5.1, using settings 'hello.settings'
Development server is running at http://example.com:8000/
Quit the server with CONTROL-C.

Application user

Even though Django has a pretty good security track record, web applications can become compromised. If the application has limited access to resources on your server, potential damage can also be limited. Your web applications should run as system users with limited privileges.

Create a user for your app, named hello and assigned to a system group called web apps

$ sudo groupadd --system webapps
$ sudo useradd --system --gid webapps --home /webapps/hello_django hello 
Gunicorn

In production we won’t be using Django’s single-threaded development server, but a dedicated application server called gunicorn.

Install gunicorn in your application’s virtual environment:
(hello_django) $ pip install gunicorn
Downloading/unpacking gunicorn
  Downloading gunicorn-0.17.4.tar.gz (372Kb): 372Kb downloaded
  Running setup.py egg_info for package gunicorn

Installing collected packages: gunicorn
  Running setup.py install for gunicorn

    Installing gunicorn_paster script to /webapps/hello_django/bin
    Installing gunicorn script to /webapps/hello_django/bin
    Installing gunicorn_django script to /webapps/hello_django/bin
Successfully installed gunicorn
Cleaning up...

安装好gunicoin,运行django程序:

(hello_django) $ gunicorn hello.wsgi:application --bind example.com:8001

http://michal.karzynski.pl/blog/2013/06/09/django-nginx-gunicorn-virtualenv-supervisor/

python manage.py runserver 27.54.250.15:8000

gunicorn hello.wsgi:application –bind 27.54.250.15:8001
Directadmin

1. 安装gcc, gcc-c++

yum install gcc
CODE

yum install gcc-c++
想当然第一次装的时候, 是一个header, 一个header,??一个RPM, 一个RPM慢慢装的啊, 哪里知道这两条命令就能全搞定. 幸好遇到这个新的公司的这个技术, 要不然还不一辈子当傻子了?

2. 之后开始安装DirectAdmin了, 其实只是按官方步骤就OK了, 我只是用中文转述一下, 哈哈.

安装之前请一定准备好DirectAdmin的授权信息, client ID, license ID, 并确定使用系统和IP都是正确的. 否则无法成功安装

1)用root帐号登录系统, 下载setup.sh文件, 运行

wget http://www.directadmin.com/setup.sh
2)改setup.sh属性,

chmod 755 setup.sh
3)运行程序

./setup.sh

Linux下python升级步骤

  首先下载源tar包

  可利用linux自带下载工具wget下载,如下所示:

1
# wget http://www.python.org/ftp/python/3.3.0/Python-3.3.0.tgz
  或自己去网上找,这里提供一个最新版的下载链接:http://xiazai.zol.com.cn/detail/33/320958.shtml

  这里我用的是第二种方法,下载的是Python-3.1.2.tar.bz2版本,下载完成后到下载目录下,解压

1
bunzip2 Python-3.1.2.tar.bz2
2
tar -xvf Python-3.1.2.tar(若是第一种方法,则直接解压缩tar -xzvf Python-3.3.0.tgz)
  进入解压缩后的文件夹

1
cd Python-3.1.2
  在编译前先在/usr/local建一个文件夹python3(作为python的安装路径,以免覆盖老的版本)

1
mkdir /usr/local/python3
  开始编译安装

1
 ./configure --prefix=/usr/local/python3
2
make
3
 make install
  此时没有覆盖老版本,再将原来/usr/bin/python链接改为别的名字

1
 mv /usr/bin/python /usr/bin/python_old
  再建立新版本python的链接

1
 ln -s /usr/local/python3/bin/python3 /usr/bin/python
  这个时候输入

1
python
  就会显示出python的新版本信息

Python Base

''' use a function to number the entries in any list'''

def numberList(items):
    '''Print each item in a list items, numbered in order.'''
    number = 1
    for item in items:
        print(number, item)
        number = number + 1

def main():
    numberList(['red', 'orange', 'yellow', 'green'])
    print()
    numberList(['apples', 'pears', 'bananas'])

main()


result

1 red
2 orange
3 yellow
4 green

1 apples
2 pears
3 bananas
def listOnOneLine(items):
    for item in items:
        print(item, end=' ')
    print()

listOnOneLine(['apple', 'banana', 'pear'])
print('This is probably better!')

>>>
apple banana pear
This is probably better!
>>>

>>> nums = range(4, 9, 2)
>>> list(nums)
[4, 6, 8]
#!/usr/bin/env python3

import cgi   # NEW

def main(): # NEW except for the call to processInput
    form = cgi.FieldStorage()      # standard cgi script lines to here!
    
    # use format of next two lines with YOUR names and default data
    numStr1 = form.getfirst("x", "0") # get the form value associated with form
                                   # name 'x'.  Use default "0" if there is none. 
    numStr2 = form.getfirst("y", "0") # similarly for name 'y'
    contents = processInput(numStr1, numStr2)   # process input into a page
    print(contents)
    
def processInput(numStr1, numStr2):  
    '''Process input parameters and return the final page as a string.'''
    num1 = int(numStr1) # transform input to output data
    num2 = int(numStr2)
    total = num1+num2
    return fileToStr('additionTemplate.html').format(**locals())

# standard code for future cgi scripts from here on
def fileToStr(fileName): 
    """Return a string containing the contents of the named file."""
    fin = open(fileName); 
    contents = fin.read();  
    fin.close() 
    return contents

try:   # NEW
    print("Content-type: text/html\n\n")   # say generating html
    main() 
except:
    cgi.print_exception()                 # catch and print errors

WeB App服务端一些相关知识RestFul API

The term cloud actually has a number of meanings and discrete forms besides simple data storage.

 Software as a Service (SaaS) means applications hosted on a server that you could access and use almost as if they were installed on your local device. SaaS also to some means web application programming interfaces (APIs) that you can access remotely. Some examples of SaaS include Salesforce (www.salesforce.com), a customer relationship management (CRM) service, and GoToMeeting (www.gotomeeting.com), an online virtual meeting service.
 Infrastructure as a Service (IaaS) means the hosting of real or virtualized systems. If you need a Linux machine, for example, you can have a virtual server built
and hosted in the cloud with IaaS, removing the responsibility of building and maintaining the hardware yourself (whether that hardware is real or virtual doesn’t really matter in this model; you don’t care as the client of IaaS and in
fact may not even know). The benefit of this is that most of the responsibility for maintaining servers, worrying about updates, ensuring proper virus protection is in place, and so on, are dealt with by the provider, allowing you to focus on what really matters most to you, namely, your business. Some examples of IaaS include Amazon EC2 (http://aws.amazon.com/ec2) and Google App Engine (http://developers.google.com/appengine).
 Platform as a Service (PaaS) is effectively an extension of IaaS where instead of just a virtualized server you get a virtualized “full stack” including things such as databases, web/app servers, and programming execution environments. Examples of PaaS include IBM’s SmartCloud Application Services (www.ibm.com/cloud-computing/us/en/paas.html) and VCE’s VBLOCK (www.vce.com/products/vblock/overview).
6 CHAPTER 1: Designing My Mobile Organizer
 Network as a Service (NaaS) includes capabilities such as VPNs and “bandwidth on demand.” Once again, this removes the need to administer the hardware and/or software for your networking capabilities yourself. Any VPN, such as GigaNews’ VyprVPN (www.giganews.com/vyprvpn), is an example of NaaS.
 Storage as a Service (also abbreviated SaaS) is similar to IaaS but deals specifically with data storage. Sites such as Dropbox, Google Drive, and Microsoft’s SkyDrive are all examples of SaaS.


When you start to look at the mobile web libraries available, you’ll come across a number of options. There’s Sencha Touch (www.sencha.com), which is a very good library designed specifically for mobile web development. It allows us to develop screens using JavaScript and provides things such as widgets (grids, buttons, calendars, and so on) as well as a robust data-handling module, among lots of other things.
There’s DHTMLX Touch (www.dhtmlx.com) that provides a full HTML5-based framework and widget set for developing mobile applications.
There are also some old favorites like Dojo (www.dojotoolkit.org) and Yahoo’s YUI (www.yuilibrary.com) that, while not exclusively mobile-oriented, are capable of helping develop mobile web apps nonetheless.
However, one of the most popular general JavaScript libraries in existence (many polls indicate it is in fact the most popular) is jQuery (www.jquery.com). As a more general-purpose JavaScript library, however, jQuery isn’t focused on mobile development. Although not an all-inclusive description,probably the main goal of jQuery is to make Document Object Model (DOM) manipulation easier, and it does this exceedingly well. It’s extremely fast, lightweight, and, most importantly for the purposes of this discussion, extensible.
That extensibility comes into play with jQuery Mobile (www.jquerymobile.com), which is built on top of jQuery. This library is an HTML5-based system for developing mobile UIs. It contains widgets and helper functions for putting such apps together, among other things

Server-Side Architecture

With the client-side decisions of mobile web app using jQuery Mobile decided, how do we build the server side? Clearly, there’s a ton of choices there too.
Do you already know Java (www.oracle.com)? Then that might be a good choice. What about PHP (http://us.php.net)? Again, there’s nothing wrong with PHP in my mind, even though some would argue that it isn’t appropriate for “professional” development. I’m not here to pass judgment, though! If you know PHP already, then it’s certainly worth considering. Are Microsoft technologies (www.microsoft.com) up your alley? If that’s a skill set you already have, then they are not a bad choice. Ruby on Rails (www.rubyonrails.org) perhaps? Yes, it’s worthy of consideration certainly, as are any of a dozen other possible technologies you might come across.
All of these also require potentially significant server infrastructures. Java requires an entire servlet container. PHP is an extension to an existing web server. Microsoft of course requires IIS, its proprietary web server, plus the appropriate extensions. Ruby on Rails is its own server product essentially. All of these also require administration expertise and are therefore somewhat complex to work with, depending on what you might already know.
At the end of the day, there’s another option that’s fast becoming very popular, and for good reason: node.js (www.nodejs.org). One of the key benefits to node.js is that the code you write on the server side is written in JavaScript, just as your client-side code is. Since one of the reasons I stated for going with a mobile web approach is reuse of skills, shouldn’t that apply to the server side as well?
I think so! The idea of the same language on both sides of the conversation, meaning client side and server side, and assuming performance isn’t a problem, is attractive to many people.
The other big benefit of node.js is that it is designed for high performance and concurrency from the start. While neither of these concerns is particularly big for My Mobile Organizer frankly, there’s no good reason to use technologies that hamstring us in either regard.

What About the Database?

Of course, just deciding on node.js for the server side isn’t quite the whole story. There’s also data storage to consider. We need a database of some sort too, don’t we?
Of course we do!
26 CHAPTER 1: Designing My Mobile Organizer
So then, which do we use? Oracle (www.oracle.com)? It’s a great database supporting tons of massive, high-availability systems out there. Yet, it’s expensive, so it’s probably not the best choice for our relatively minor app. What about the popular MySQL (www.mysql.com)? It’s very good, no question; I use it tons myself. To make a long story short, there are many choices to choose from in this area, too many to name.
Given that we’ve decided on node.js, are there any options that work well with it? Yes, all of the above in fact can be used with it. There’s another choice, though, that is very popular and is part of the “NoSQL” movement: MongoDB.
The NoSQL movement is an approach to data storage that eschews the need for Structured Query Language (SQL) that all relational database management systems (RDBMSs) are based upon. It’s fundamentally different in that you store “documents,” as opposed to relational data in the form
of tables and rows of data. It goes along fantastically well with JavaScript, and therefore node.js, because a “document” can be simply an object represented with JSON, which of course is native, even the lingua franca really, of JavaScript. MongoDB is one very popular implementation of this concept, and it integrates exceedingly well with node.js.
Chapter 6 is where we’ll deep-dive into MongoDB so for now, suffice to say that its NoSQL approach, and the simple API made available to our node.js app for it, makes it easy to work with and provides a good data storage mechanism for our PIM app.

his stack, the combination of PhoneGap, jQuery, jQuery Mobile, node.js, REST, and MongoDB, is rapidly becoming a popular one because it is flexible, is easy to learn, performs well (if you do your job as a developer reasonably well at least), and is based on open, free technologies.

All About Core Data–NSManagedObjectContextDidSaveNotification

Core Data sits between your application and a persistent store, which is the generic term given to a data file such as an SQLite database, XML file (which can’t be used as a persistent store on iOS), or Binary (atomic) store. These files are called “persistent” because they can survive the underlying hardware being reset.

A persistent store coordinator can have multiple persistent stores

a managed object model is shown sitting between a persistent store coordinator and a managed object context.

The NSMainQueueConcurrencyType should be used when you want the context to operate on the main thread. Any heavy work performed in this queue may slow down or even freeze the user interface. You need at least one context working in the foreground to update user interface elements.
■ The NSPrivateQueueConcurrencyType should be used when you don’t want the context to operate on the main thread. This is an ideal concurrency type for potentially heavy work, such as saving or importing data.
■ The NSConfinementConcurrencyType is the default legacy option, which you should typically avoid unless you need backward compatibility with pre–iOS 5.0 devices.


The sqlite file is the database file, as per usual.
■ The sqlite-wal file is the Write-Ahead Log file containing uncommitted database transactions. If you delete this file, you will lose data. If this file does not exist, there are no pending transactions waiting to be committed.
■ The sqlite-shm file is the Shared Memory file containing an index of the WAL file. This file can be regenerated automatically so you don’t need to worry about it.


A deep copy involves copying managed objects and their relationships from one persistent store to another.

How would you watch a document’s managedObjectContext?!
 - (void)viewDidAppear:(BOOL)animated
 {
     [super viewDidAppear:animated];
     [center addObserver:self
                selector:@selector(contextChanged:)
                    name:NSManagedObjectContextDidSaveNotification
object:document.managedObjectContext]; //don’tpassnilhere!
 }
 - (void)viewWillDisappear:(BOOL)animated
 {
     [center removeObserver:self
                       name:NSManagedObjectContextDidSaveNotification
                     object:document.managedObjectContext];
     [super viewWillDisappear:animated];
 }
NSManagedObjectContextDidSaveNotification !
  - (void)contextChanged:(NSNotification *)notification
  {
// The notification.userInfo object is an NSDictionary with the following keys: NSInsertedObjectsKey // an array of objects which were inserted NSUpdatedObjectsKey // an array of objects whose attributes changed NSDeletedObjectsKey // an array of objects which were deleted
}!
Merging changes!
If you get notified that another NSManagedObjectContext has changed your database ...! ... you can just refetch (if you haven’t changed anything in your NSMOC, for example).!
... or you can use the NSManagedObjectContext method:!
- (void)mergeChangesFromContextDidSaveNotification:(NSNotification *)notification;

[_myAppDelegate.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];

Deletion

Deleting objects from the database is easy (sometimes too easy!)! [aDocument.managedObjectContext deleteObject:photo]; !
Make sure that the rest of your objects in the database are in a sensible state after this.! Relationships will be updated for you (if you set Delete Rule for relationship attributes properly).! And don’t keep any strong pointers to photo after you delete it!!
prepareForDeletion !
This is another method we sometimes put in a category of an NSManagedObject subclass ...!
  @implementation Photo (Deletion)
  - (void)prepareForDeletion
  {
// we don’t need to set our whoTook to nil or anything here (that will happen automatically)!
// but if Photographer had, for example, a “number of photos taken” attribute,!
// we might adjust it down by one here (e.g. self.whoTook.photoCount--). }
@end

Querying

Creating an NSFetchRequest!
We’ll consider each of these lines of code one by one ...
 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@“Photo”];
 request.fetchBatchSize = 20;
 request.fetchLimit = 100;
 request.sortDescriptors = @[sortDescriptor];
 request.predicate = ...;
Specifying the kind of Entity we want to fetch! A given fetch returns objects all of the same Entity.!
You can’t have a fetch that returns some Photos and some Photographers (it’s one or the other).! Setting fetch sizes/limits!
If you created a fetch that would match 1000 objects, the request above faults 20 at a time. And it would stop fetching after it had fetched 100 of the 1000

NSPredicate !

This is the guts of how we specify exactly which objects we want from the database.!
Predicate formats!
Creating one looks a lot like creating an NSString, but the contents have semantic meaning.
  NSString *serverName = @“flickr-5”;
  NSPredicate *predicate =
      [NSPredicate predicateWithFormat:@“thumbnailURL contains %@”, serverName];
Examples!
@“uniqueId = %@”, [flickrInfo objectForKey:@“id”] // unique a photo in the database @“name contains[c] %@”, (NSString *) // matches name case insensitively!
@“viewed > %@”, (NSDate *) // viewed is a Date attribute in the data mapping! @“whoTook.name = %@”, (NSString *) // Photo search (by photographer’s name)!
@“any photos.title contains %@”, (NSString *) // Photographer search (not a Photo search)! Many more options. Look at the class documentation for NSPredicate.

NSCompoundPredicate

NSCompoundPredicate !
You can use AND and OR inside a predicate string, e.g. @“(name = %@) OR (title = %@)”! Or you can combine NSPredicate objects with special NSCompoundPredicates.
NSArray *array = @[predicate1, predicate2];
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:array]; This predicate is “predicate1 AND predicate2”. Or available too, of course

Advanding Querying

Key Value Coding!
Can actually do predicates like @“photos.@count > 5” (Photographers with more than 5 photos).! @count is a function (there are others) executed in the database itself.! https://developer.apple.com/library/ios/documentation/cocoa/conceptual/KeyValueCoding/Articles/CollectionOperators.html.!
By the way, all this stuff (and more) works on dictionaries, arrays and sets too ...!
e.g. <strong>[propertyListResults valueForKeyPath:@“photos.photo.@avg.latitude”]</strong> on Flickr results!
returns the average latitude of all of the photos in the results (yes, really)!
e.g. @“photos.photo.title.length" would return an array of the lengths of the titles of the photos!

Example!

Let’s say we want to query for all Photographers ...!
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@“Photographer”];
... who have taken a photo in the last 24 hours ...!
NSDate *yesterday = [NSDate dateWithTimeIntervalSinceNow:-24*60*60]; !
request.predicate = [NSPredicate predicateWithFormat:@“any photos.uploadDate > %@”, yesterday]; ! ... sorted by the Photographer’s name ...
request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@“name” ascending:YES]];

How do you create an NSFetchedResultsController?

Just need the NSFetchRequest to drive it (and a NSManagedObjectContext to fetch from).
Let's say we want to show all photos taken by someone with the name photogName in our table:
 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@“Photo”];
 request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@“title” ...]];
 request.predicate = [NSPredicate predicateWithFormat:@“whoTook.name = %@”, photogName];
 NSFetchedResultsController *frc = [[NSFetchedResultsController alloc]
     initWithFetchRequest:(NSFetchRequest *)request
     managedObjectContext:(NSManagedObjectContext *)context
       sectionNameKeyPath:(NSString *)keyThatSaysWhichSectionEachManagedObjectIsIn
                cacheName:@“MyPhotoCache”];  // careful!
Be sure that any cacheName you use is always associated with exactly the same request. It’s okay to specify nil for the cacheName (no cacheing of fetch results in that case).
It is critical that the sortDescriptor matches up with the keyThatSaysWhichSection...
The results must sort such that all objects in the first section come first, second second, etc

NSFetchedResultController–CoreDataTableViewController

//
//  CoreDataTableViewController.h
//
//  Created for Stanford CS193p Fall 2013.
//  Copyright 2013 Stanford University. All rights reserved.
//
// This class mostly just copies the code from NSFetchedResultsController's documentation page
//   into a subclass of UITableViewController.
//
// Just subclass this and set the fetchedResultsController.
// The only UITableViewDataSource method you'll HAVE to implement is tableView:cellForRowAtIndexPath:.
// And you can use the NSFetchedResultsController method objectAtIndexPath: to do it.
//
// Remember that once you create an NSFetchedResultsController, you CANNOT modify its @propertys.
// If you want new fetch parameters (predicate, sorting, etc.),
//  create a NEW NSFetchedResultsController and set this class's fetchedResultsController @property again.
//

#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>

@interface CoreDataTableViewController : UITableViewController <NSFetchedResultsControllerDelegate>

// The controller (this class fetches nothing if this is not set).
@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;

// Causes the fetchedResultsController to refetch the data.
// You almost certainly never need to call this.
// The NSFetchedResultsController class observes the context
//  (so if the objects in the context change, you do not need to call performFetch
//   since the NSFetchedResultsController will notice and update the table automatically).
// This will also automatically be called if you change the fetchedResultsController @property.
- (void)performFetch;

// Set to YES to get some debugging output in the console.
@property BOOL debug;

@end

//
//  CoreDataTableViewController.m
//
//  Created for Stanford CS193p Fall 2013.
//  Copyright 2013 Stanford University. All rights reserved.
//

#import "CoreDataTableViewController.h"

@implementation CoreDataTableViewController

#pragma mark - Fetching

- (void)performFetch
{
    if (self.fetchedResultsController) {
        if (self.fetchedResultsController.fetchRequest.predicate) {
            if (self.debug) NSLog(@"[%@ %@] fetching %@ with predicate: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.fetchedResultsController.fetchRequest.entityName, self.fetchedResultsController.fetchRequest.predicate);
        } else {
            if (self.debug) NSLog(@"[%@ %@] fetching all %@ (i.e., no predicate)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.fetchedResultsController.fetchRequest.entityName);
        }
        NSError *error;
        BOOL success = [self.fetchedResultsController performFetch:&error];
        if (!success) NSLog(@"[%@ %@] performFetch: failed", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
        if (error) NSLog(@"[%@ %@] %@ (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), [error localizedDescription], [error localizedFailureReason]);
    } else {
        if (self.debug) NSLog(@"[%@ %@] no NSFetchedResultsController (yet?)", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
    }
    [self.tableView reloadData];
}

- (void)setFetchedResultsController:(NSFetchedResultsController *)newfrc
{
    NSFetchedResultsController *oldfrc = _fetchedResultsController;
    if (newfrc != oldfrc) {
        _fetchedResultsController = newfrc;
        newfrc.delegate = self;
        if ((!self.title || [self.title isEqualToString:oldfrc.fetchRequest.entity.name]) && (!self.navigationController || !self.navigationItem.title)) {
            self.title = newfrc.fetchRequest.entity.name;
        }
        if (newfrc) {
            if (self.debug) NSLog(@"[%@ %@] %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), oldfrc ? @"updated" : @"set");
            [self performFetch];
        } else {
            if (self.debug) NSLog(@"[%@ %@] reset to nil", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
            [self.tableView reloadData];
        }
    }
}

#pragma mark - UITableViewDataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    NSInteger sections = [[self.fetchedResultsController sections] count];
    return sections;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSInteger rows = 0;
    if ([[self.fetchedResultsController sections] count] > 0) {
        id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
        rows = [sectionInfo numberOfObjects];
    }
    return rows;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
	return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
}

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
	return [self.fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
    return [self.fetchedResultsController sectionIndexTitles];
}

#pragma mark - NSFetchedResultsControllerDelegate

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller
  didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
		   atIndex:(NSUInteger)sectionIndex
	 forChangeType:(NSFetchedResultsChangeType)type
{
    switch(type)
    {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
            
        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controller:(NSFetchedResultsController *)controller
   didChangeObject:(id)anObject
	   atIndexPath:(NSIndexPath *)indexPath
	 forChangeType:(NSFetchedResultsChangeType)type
	  newIndexPath:(NSIndexPath *)newIndexPath
{		
    switch(type)
    {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
            
        case NSFetchedResultsChangeDelete:
            [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
            
        case NSFetchedResultsChangeUpdate:
            [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
            
        case NSFetchedResultsChangeMove:
            [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    [self.tableView endUpdates];
}

@end


iCloud

icloud

  • The Application Stores Directory, also known as the application sandbox, is a
    local directory that currently holds the original Grocery-Dude.sqlite store. An iCloud.sqlite store will be added to this folder in a subfolder specific to each iCloud user. The per-user subfolders are managed transparently by Core Data. The folder structure is shown at the end of the chapter in the “Exercises” section.
  • The Ubiquity Container is where iCloud documents and data specific to the authenticated iCloud user are found. Everything in this folder is synchronized automatically with the iCloud servers. If a directory with a .nosync suffix is stored
    in the ubiquity container, its contents will not be synchronized. You may have seen implementations of iCloud where the iCloud Store was placed in a .nosync folder of the ubiquity container. This approach is no longer recommended since iOS 7 because it prevents Core Data from transparently managing a Fallback Store. A Fallback Store is used to provide seamless transitions between iCloud accounts and reduce the time it takes for the iCloud Store to become usable for the first time. The Fallback Store is also used when the user is logged out of iCloud, or has disabled iCloud Documents & Data.
  • iCloud is the name of the service allowing a user’s data to be synchronized across all
    of his or her devices. It is possible to see the contents of your iCloud container for debugging purposes at https://developer.icloud.com. You can also perform metadata queries to inspect the contents of iCloud or use the iCloud Debug Navigator introduced in Xcode 5, which will be shown later in the chapter. Each application using iCloud has its own directory at the root of iCloud, and applications from the same developer can be configured to share a ubiquity container within it. This is useful if you need to maintain separate free and paid versions of an application that need to access the same data.

Create file to iCloud
Icloud’s local path from phone: file:///private/var/mobile/Library/Mobile%20Documents/TeamID~com~toogoogoo~iCloud/

iCloud’s local path from simulator: file:///Users/xushao/Library/Application%20Support/iPhone%20Simulator/7.0.3/Library/Mobile%20Documents/TeamID ~com~toogoogoo~Test/

如果在该目录手动创建文件,icloud也会同步创建

NSURL * iCloudURL = [self.fManager URLForUbiquityContainerIdentifier:nil];这个url的目录为:根目录

//
//  iCloudAppDelegate.m
//  iCloud
//
//  Created by xushao on 2/24/14.
//  Copyright (c) 2014 TGG. All rights reserved.
//

#import "iCloudAppDelegate.h"

@interface iCloudAppDelegate ()
@property(nonatomic, strong)NSFileManager *fManager;
@property(nonatomic, strong)NSMetadataQuery *iCloudQuery;

@end

@implementation iCloudAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    /*
    NSString *stringValuekey2 = @"My String";
    NSString *stringValueKey = @"MyStringKey";
    NSUbiquitousKeyValueStore *KVStore =  [[NSUbiquitousKeyValueStore alloc] init];
    
    if ([[KVStore stringForKey:stringValuekey2] length]==0) {
        [self alert:@"no string, settting"];
        [KVStore setString:@"this is string" forKey:stringValueKey];
        [KVStore setString:@"stringValuekey2" forKey:stringValuekey2];
    }else{
        [self alert:[NSString stringWithFormat:@"Result is :%@ and %@",[KVStore stringForKey:stringValueKey],[KVStore stringForKey:stringValuekey2]]];
    }
    
    
    
    
    if (![fManager fileExistsAtPath:[[self documentURL] path]]) {
        
        [self alert:[NSString stringWithFormat:@"createDirectoryAtPath %@ ", [self documentURL]]];
        [fManager createDirectoryAtPath:[[self documentURL] path] withIntermediateDirectories:YES attributes:nil error:nil];
    }else{
        [self alert:@"File already exit"];
    }
     

    if (![self.fManager fileExistsAtPath:[[self documentURL] path]]) {
        
        [self alert:[NSString stringWithFormat:@"createDirectoryAtURL %@ ", [self documentURL]]];
        
        [self.fManager createDirectoryAtURL:[self documentURL] withIntermediateDirectories:YES
                                 attributes:nil error:nil  ];
        //[self.fManager createDirectoryAtPath:[[self documentURL] path] withIntermediateDirectories:YES attributes:nil error:nil];
    }else{
        [self alert:@"File already exit"];
    }
     */
    self.fManager = [NSFileManager defaultManager];
   NSString * TeamID = @"FUHS6YZAHW";
    NSString *buddleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
    NSString *identifier = [NSString stringWithFormat:@"%@.%@", TeamID, buddleIdentifier];
    
    
   NSURL * iCloudURL = [self.fManager URLForUbiquityContainerIdentifier:nil];
    NSError *error = nil;
   // NSString *documentDirec = [[iCloudURL path] stringByAppendingPathComponent:@"Documents"];
    NSURL *documentURL = [iCloudURL URLByAppendingPathComponent:@"Documents" isDirectory:YES];
    //NSString *createDocument = [documentDirec stringByAppendingPathComponent:@"David"];
    if (![self.fManager fileExistsAtPath:[documentURL path]]) {
        
        
        [self.fManager createDirectoryAtPath:[documentURL path] withIntermediateDirectories:YES attributes:nil error:&error];
        if (!error) {
            [self alert:[NSString stringWithFormat:@"create iCloudURL: %@ ", iCloudURL]];
            NSLog(@"%@",iCloudURL);
        }else{
            NSLog(@"error1");
        }
        
    }else{
        
        NSString *textString = @"This is text";
        NSURL *FileURL = [documentURL URLByAppendingPathComponent:@"latest.text"];
       // NSString *path = [documentURL stringByAppendingPathComponent:@"JacobString.sql"];
        NSError *error = nil;
        if ([textString writeToURL:FileURL atomically:YES encoding:NSUTF8StringEncoding error:&error]) {
            if (!error) {
                //NSData *data = [self.fManager contentsAtPath:path];
                //NSString *string = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
                //[self alert:[NSString stringWithFormat:@"The content is : %@", string]];
            }else{
                 NSLog(@"error2");
            }
        }else{
            [self alert:@"Couldn't write to"];
        }
    }
    
    
    //
    NSURL *fileURL = [[self documentURL] URLByAppendingPathComponent:@"JacobLocal.String.txt"];
    if ([self.fManager fileExistsAtPath:[fileURL path]]) {
        if ([self.fManager setUbiquitous:YES itemAtURL:fileURL destinationURL:documentURL error:&error]) {
            if (!error) {
                NSLog(@"successful upload");
            }else{
                NSLog(@"error3");
            }
        }else{
            NSLog(@"couldn't");
        }
        
    }
    
    if ([self.iCloudQuery startQuery]) {
        [self alert:@"start query"];
    }else{
        NSLog(@"not query");
    }
    
    
    return YES;
    
}

-(NSMetadataQuery *)iCloudQuery
{
    if (!_iCloudQuery) {
        _iCloudQuery = [[NSMetadataQuery alloc] init];
        _iCloudQuery.searchScopes = [NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope];
        _iCloudQuery.predicate = [NSPredicate predicateWithFormat:@"%K LIKE '*'",NSMetadataItemFSNameKey];
        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(preocessQueryResult:) name:NSMetadataQueryDidFinishGatheringNotification object:_iCloudQuery];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(preocessQueryResult:) name:NSMetadataQueryDidUpdateNotification object:_iCloudQuery];
    
    }
    
    return _iCloudQuery;
}

-(void)preocessQueryResult:(NSNotification *)notification{
    [self.iCloudQuery disableUpdates];
    NSMutableArray *UrlArray = [[NSMutableArray alloc] init];
    NSUInteger resultIndex = [self.iCloudQuery resultCount];
    NSLog(@"resultIndex is %d",resultIndex);

    for (int i = 0; i < resultIndex; i++) {
        NSMetadataItem *item = [self.iCloudQuery resultAtIndex:i];
        NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];

        [UrlArray addObject:[url pathComponents]];
    }
    
    [self.iCloudQuery enableUpdates];
}

-(NSURL *)documentURL{
    NSURL *documentDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    return [documentDirectory URLByAppendingPathComponent:@"TGGDocument"];
}

-(void)alert:(NSString *)msg{
    
    [[[UIAlertView alloc] initWithTitle:@"Noticed" message:msg delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] show];
}
	

DocumentTVC

//
// DocumentTVC.m
// Test
//
// Created by xushao on 2/23/14.
// Copyright (c) 2014 TGG. All rights reserved.
//

#import “DocumentTVC.h”

@interface DocumentTVC ()
@property(nonatomic, strong)NSArray *documents;
@property(nonatomic, strong)NSMetadataQuery *icloudQuery;
@end

@implementation DocumentTVC

-(void)viewDidLoad
{
if (DEBUG == 1) {
NSLog(@”%@ is %@”,self.class, NSStringFromSelector(_cmd));
}
[super viewDidLoad];
NSLog(@”%@”, [self iCloudURL]);
}
-(NSURL *)iCloudURL{
return [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
}

@synthesize documents = _documents;

-(void)setDocuments:(NSArray *)documents
{
_documents = documents;
[self.tableView reloadData];
}

-(void)processIcloudqueryResult:(NSNotification *)notificatin{
[self.icloudQuery disableUpdates];

NSUInteger resultCount = [self.icloudQuery resultCount];

for (int i = 0; i < resultCount; i ++) {
NSMetadataItem *item = [self.icloudQuery resultAtIndex:i];
NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
}
}

/* [item valueForAttribute:NSMetadataItemURLKey];

NSString * const NSMetadataItemFSNameKey;
NSString * const NSMetadataItemDisplayNameKey;
NSString * const NSMetadataItemURLKey;
NSString * const NSMetadataItemPathKey;
NSString * const NSMetadataItemFSSizeKey;
NSString * const NSMetadataItemFSCreationDateKey;
NSString * const NSMetadataItemFSContentChangeDateKey;
*/

-(NSMetadataQuery *)icloudQuery
{
if (!_icloudQuery) {
_icloudQuery = [[NSMetadataQuery alloc] init];
_icloudQuery.searchScopes = [NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope];
//NSString * const NSMetadataQueryUbiquitousDocumentsScope;
// NSString * const NSMetadataQueryUbiquitousDataScope;

_icloudQuery.predicate = [NSPredicate predicateWithFormat:@"%K like '*'",NSMetadataItemFSNameKey ];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(processIcloudqueryResult:) name:NSMetadataQueryDidFinishGatheringNotification object:_icloudQuery];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(processIcloudqueryResult:) name:NSMetadataQueryDidUpdateNotification object:_icloudQuery];

}

return _icloudQuery;
}

-(void)viewWillAppear:(BOOL)animated
{

[super viewWillAppear:animated];
if (![self.icloudQuery isStarted]) {
[self.icloudQuery enableUpdates];
}

}

-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.icloudQuery disableUpdates];
}

#pragma mark - Table view data source

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.documents count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Document Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

// Configure the cell...
cell.textLabel.text = [[self.documents objectAtIndex:indexPath.row] lastPathComponent];
return cell;
}

/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/

/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/

/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/

/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/

/*
#pragma mark - Navigation

// In a story board-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}

*/

@end

IOS7-CoreDAta:DeepCopy

deepCopy


The existing _importContext will be reused as the target context for the deep copy demon- stration. Copying an object to another context isn’t as straightforward as a copy-and-paste command. To copy an object, you actually need to create a new object in the target context and then copy all the attribute values from a source object to the new object. That leaves the relationships, which can’t be copied in the same way. If you were to copy a relationship the same way you copied an attribute value, you would end up with an illegal cross-store relation- ship between the copied object and object(s) in the source store. Instead of copying a relation- ship, a deep copy needs to identify related copied objects in the target context and then establish a relationship to them from the copied object. Figure 9.2 illustrates a To-One relationship copy.

enumerateObjectsUsingBlock详解

NSArray *anArray=[NSArray arrayWithObjects:@"This", @"is", @"a", @"test", nil]; 
NSString *string=@"test";
[anArray enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop)
{
  if([obj localizedCaseInsensitiveCompare:string] == NSOrderedSame)
  {
    // 对返回的obj做点别的事情
  *stop=YES;

  }

要是anArray对象中有个单词是@”test”,那么就把指针*stop设置为YES,以通知anArray对象提前停止枚举。块除了id obj和BOOL *stop参数,还有一个NSUInteger index参数。index参数让块中的算法知道当前元素的位置,这对这样的并发枚举非常有用。要是没有这个参数,访问索引的唯一方式就是使用indexOfObject:方法,这样影响效率

IOS7-CoreDAta案例:PrepareTVC与shopTVC,ItemVC,Unite,UnitePicker,CoreDataTVC

The NSMainQueueConcurrencyType should be used when you want the context to operate on the main thread. Any heavy work performed in this queue may slow down or even freeze the user interface. You need at least one context working in the foreground to update user interface elements.
■ The NSPrivateQueueConcurrencyType should be used when you don’t want the context to operate on the main thread. This is an ideal concurrency type for potentially heavy work, such as saving or importing data.

The sqlite file is the database file, as per usual.
■ The sqlite-wal file is the Write-Ahead Log file containing uncommitted database transactions. If you delete this file, you will lose data. If this file does not exist, there are no pending transactions waiting to be committed.
■ The sqlite-shm file is the Shared Memory file containing an index of the WAL file. This file can be regenerated automatically so you don’t need to worry about it.

#import &lt;Foundation/Foundation.h&gt;
#import &lt;CoreData/CoreData.h&gt;
#import "MigrationVC.h"

@interface CoreDataHelper : NSObject &lt;UIAlertViewDelegate,NSXMLParserDelegate&gt;

@property (nonatomic, readonly) NSManagedObjectContext       *parentContext;
@property (nonatomic, readonly) NSManagedObjectContext       *context;
@property (nonatomic, readonly) NSManagedObjectContext       *importContext;

@property (nonatomic, readonly) NSManagedObjectModel         *model;
@property (nonatomic, readonly) NSPersistentStoreCoordinator *coordinator;
@property (nonatomic, readonly) NSPersistentStore            *store;

@property (nonatomic, readonly) NSManagedObjectContext       *sourceContext;
@property (nonatomic, readonly) NSPersistentStoreCoordinator *sourceCoordinator;
@property (nonatomic, readonly) NSPersistentStore            *sourceStore;

@property (nonatomic, readonly) NSPersistentStore            *iCloudStore;

@property (nonatomic, retain) MigrationVC *migrationVC;

@property (nonatomic, retain) UIAlertView *importAlertView;

@property (nonatomic, strong) NSXMLParser *parser;

@property (nonatomic, strong) NSTimer *importTimer;

- (void)setupCoreData;
- (void)saveContext;
- (void)backgroundSaveContext;
- (BOOL)reloadStore;
- (NSURL *)applicationStoresDirectory;

- (BOOL)iCloudAccountIsSignedIn;
- (void)ensureAppropriateStoreIsLoaded;
@end

CoreDataHelper.m

#import "CoreDataHelper.h"
#import "CoreDataImporter.h"
#import "Faulter.h"

@implementation CoreDataHelper
#define debug 1

#pragma mark - FILES
NSString *storeFilename = @"Grocery-Dude.sqlite";
NSString *sourceStoreFilename = @"DefaultData.sqlite";
NSString *iCloudStoreFilename = @"iCloud.sqlite";

#pragma mark - PATHS
- (NSString *)applicationDocumentsDirectory {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class,NSStringFromSelector(_cmd));
    }
    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES) lastObject];
}
- (NSURL *)applicationStoresDirectory {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }

    NSURL *storesDirectory =
    [[NSURL fileURLWithPath:[self applicationDocumentsDirectory]]
     URLByAppendingPathComponent:@"Stores"];

    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath:[storesDirectory path]]) {
        NSError *error = nil;
        if ([fileManager createDirectoryAtURL:storesDirectory
                  withIntermediateDirectories:YES
                                   attributes:nil
                                        error:&amp;error]) {
            if (debug==1) {
                NSLog(@"Successfully created Stores directory");}
        }
        else {NSLog(@"FAILED to create Stores directory: %@", error);}
    }
    return storesDirectory;
}
- (NSURL *)storeURL {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    return [[self applicationStoresDirectory]
            URLByAppendingPathComponent:storeFilename];
}
- (NSURL *)sourceStoreURL {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }

    return [NSURL fileURLWithPath:[[NSBundle mainBundle]
                                   pathForResource:[sourceStoreFilename stringByDeletingPathExtension]
                                   ofType:[sourceStoreFilename pathExtension]]];
}
- (NSURL *)iCloudStoreURL {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    return [[self applicationStoresDirectory]
            URLByAppendingPathComponent:iCloudStoreFilename];
}

#pragma mark - SETUP
- (id)init {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    self = [super init];
    if (!self) {return nil;}

    _model = [NSManagedObjectModel mergedModelFromBundles:nil];
    _coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_model];

    _parentContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [_parentContext performBlockAndWait:^{
        [_parentContext setPersistentStoreCoordinator:_coordinator];
        [_parentContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
    }];

    _context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [_context setParentContext:_parentContext];
    [_context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];

    _importContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [_importContext performBlockAndWait:^{
        [_importContext setParentContext:_context];
        [_importContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
        [_importContext setUndoManager:nil]; // the default on iOS
    }];

    //_sourceCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_model];
    _sourceContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [_sourceContext performBlockAndWait:^{
        [_sourceContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
        [_sourceContext setParentContext:_context];
        [_sourceContext setUndoManager:nil]; // the default on iOS
    }];

    [self listenForStoreChanges];

    return self;
}
- (void)loadStore {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (_store) {return;} // Don’t load store if it’s already loaded

    BOOL useMigrationManager = NO;
    if (useMigrationManager &amp;&amp;
        [self isMigrationNecessaryForStore:[self storeURL]]) {
        [self performBackgroundManagedMigrationForStore:[self storeURL]];
    } else {
        NSDictionary *options =
        @{
          NSMigratePersistentStoresAutomaticallyOption:@YES
          ,NSInferMappingModelAutomaticallyOption:@YES
          ,NSSQLitePragmasOption: @{@"journal_mode": @"DELETE"} // Uncomment to disable WAL journal mode
          };
        NSError *error = nil;
        _store = [_coordinator addPersistentStoreWithType:NSSQLiteStoreType
                                            configuration:nil
                                                      URL:[self storeURL]
                                                  options:options
                                                    error:&amp;error];
        if (!_store) {
            NSLog(@"Failed to add store. Error: %@", error);abort();
        }
        else         {NSLog(@"Successfully added store: %@", _store);}
    }

}
- (void)loadSourceStore {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (_sourceStore) {return;} // Don’t load source store if it's already loaded

    NSDictionary *options =
    @{
      NSReadOnlyPersistentStoreOption:@YES
      };
    NSError *error = nil;
    _sourceStore =
    [_sourceCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                     configuration:nil
                                               URL:[self sourceStoreURL]
                                           options:options
                                             error:&amp;error];
    if (!_sourceStore) {
        NSLog(@"Failed to add source store. Error: %@",
              error);abort();
    } else {
        NSLog(@"Successfully added source store: %@", _sourceStore);
    }
}
- (void)setupCoreData {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (!_store &amp;&amp; !_iCloudStore) {
        if ([self iCloudEnabledByUser]) {
            NSLog(@"** Attempting to load the iCloud Store **");
            if ([self loadiCloudStore]) {
                return;
            }
        }
        NSLog(@"** Attempting to load the Local, Non-iCloud Store **");
        [self setDefaultDataStoreAsInitialStore];
        [self loadStore];
    } else {
        NSLog(@"SKIPPED setupCoreData, there's an existing Store:\n ** _store(%@)\n ** _iCloudStore(%@)", _store, _iCloudStore);
    }
}

#pragma mark - SAVING
- (void)saveContext {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if ([_context hasChanges]) {
        NSError *error = nil;
        if ([_context save:&amp;error]) {
            NSLog(@"_context SAVED changes to persistent store");
        } else {
            NSLog(@"Failed to save _context: %@", error);
            [self showValidationError:error];
        }
    } else {
        NSLog(@"SKIPPED _context save, there are no changes!");
    }
}
- (void)backgroundSaveContext {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    // First, save the child context in the foreground (fast, all in memory)
    [self saveContext];

    // Then, save the parent context.
    [_parentContext performBlock:^{
        if ([_parentContext hasChanges]) {
            NSError *error = nil;
            if ([_parentContext save:&amp;error]) {
                NSLog(@"_parentContext SAVED changes to persistent store");
            }
            else {
                NSLog(@"_parentContext FAILED to save: %@", error);
                [self showValidationError:error];
            }
        }
        else {
            NSLog(@"_parentContext SKIPPED saving as there are no changes");
        }
    }];
}

#pragma mark - MIGRATION MANAGER
- (BOOL)isMigrationNecessaryForStore:(NSURL*)storeUrl {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (![[NSFileManager defaultManager] fileExistsAtPath:[self storeURL].path]) {
        if (debug==1) {NSLog(@"SKIPPED MIGRATION: Source database missing.");}
        return NO;
    }
    NSError *error = nil;
    NSDictionary *sourceMetadata =
    [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType
                                                               URL:storeUrl error:&amp;error];
    NSManagedObjectModel *destinationModel = _coordinator.managedObjectModel;
    if ([destinationModel isConfiguration:nil
              compatibleWithStoreMetadata:sourceMetadata]) {
        if (debug==1) {
            NSLog(@"SKIPPED MIGRATION: Source is already compatible");}
        return NO;
    }
    return YES;
}
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {

    if ([keyPath isEqualToString:@"migrationProgress"]) {

        dispatch_async(dispatch_get_main_queue(), ^{

            float progress =
            [[change objectForKey:NSKeyValueChangeNewKey] floatValue];
            self.migrationVC.progressView.progress = progress;
            int percentage = progress * 100;
            NSString *string =
            [NSString stringWithFormat:@"Migration Progress: %i%%",
             percentage];
            NSLog(@"%@",string);
            self.migrationVC.label.text = string;
        });
    }
}
- (BOOL)replaceStore:(NSURL*)old withStore:(NSURL*)new {

    BOOL success = NO;
    NSError *Error = nil;
    if ([[NSFileManager defaultManager]
         removeItemAtURL:old error:&amp;Error]) {

        Error = nil;
        if ([[NSFileManager defaultManager]
             moveItemAtURL:new toURL:old error:&amp;Error]) {
            success = YES;
        }
        else {
            if (debug==1) {NSLog(@"FAILED to re-home new store %@", Error);}
        }
    }
    else {
        if (debug==1) {
            NSLog(@"FAILED to remove old store %@: Error:%@", old, Error);
        }
    }
    return success;
}
- (BOOL)migrateStore:(NSURL*)sourceStore {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    BOOL success = NO;
    NSError *error = nil;

    // STEP 1 - Gather the Source, Destination and Mapping Model
    NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator
                                    metadataForPersistentStoreOfType:NSSQLiteStoreType
                                    URL:sourceStore
                                    error:&amp;error];

    NSManagedObjectModel *sourceModel =
    [NSManagedObjectModel mergedModelFromBundles:nil
                                forStoreMetadata:sourceMetadata];

    NSManagedObjectModel *destinModel = _model;

    NSMappingModel *mappingModel =
    [NSMappingModel mappingModelFromBundles:nil
                             forSourceModel:sourceModel
                           destinationModel:destinModel];

    // STEP 2 - Perform migration, assuming the mapping model isn't null
    if (mappingModel) {
        NSError *error = nil;
        NSMigrationManager *migrationManager =
        [[NSMigrationManager alloc] initWithSourceModel:sourceModel
                                       destinationModel:destinModel];
        [migrationManager addObserver:self
                           forKeyPath:@"migrationProgress"
                              options:NSKeyValueObservingOptionNew
                              context:NULL];

        NSURL *destinStore =
        [[self applicationStoresDirectory]
         URLByAppendingPathComponent:@"Temp.sqlite"];

        success =
        [migrationManager migrateStoreFromURL:sourceStore
                                         type:NSSQLiteStoreType options:nil
                             withMappingModel:mappingModel
                             toDestinationURL:destinStore
                              destinationType:NSSQLiteStoreType
                           destinationOptions:nil
                                        error:&amp;error];
        if (success) {
            // STEP 3 - Replace the old store with the new migrated store
            if ([self replaceStore:sourceStore withStore:destinStore]) {
                if (debug==1) {
                    NSLog(@"SUCCESSFULLY MIGRATED %@ to the Current Model",
                          sourceStore.path);}
                [migrationManager removeObserver:self
                                      forKeyPath:@"migrationProgress"];
            }
        }
        else {
            if (debug==1) {NSLog(@"FAILED MIGRATION: %@",error);}
        }
    }
    else {
        if (debug==1) {NSLog(@"FAILED MIGRATION: Mapping Model is null");}
    }
    return YES; // indicates migration has finished, regardless of outcome
}
- (void)performBackgroundManagedMigrationForStore:(NSURL*)storeURL {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }

    // Show migration progress view preventing the user from using the app
    UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    self.migrationVC =
    [sb instantiateViewControllerWithIdentifier:@"migration"];
    UIApplication *sa = [UIApplication sharedApplication];
    UINavigationController *nc =
    (UINavigationController*)sa.keyWindow.rootViewController;
    [nc presentViewController:self.migrationVC animated:NO completion:nil];

    // Perform migration in the background, so it doesn't freeze the UI.
    // This way progress can be shown to the user
    dispatch_async(
                   dispatch_get_global_queue(
                                             DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
                       BOOL done = [self migrateStore:storeURL];
                       if(done) {
                           // When migration finishes, add the newly migrated store
                           dispatch_async(dispatch_get_main_queue(), ^{
                               NSError *error = nil;
                               _store =
                               [_coordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                          configuration:nil
                                                                    URL:[self storeURL]
                                                                options:nil
                                                                  error:&amp;error];
                               if (!_store) {
                                   NSLog(@"Failed to add a migrated store. Error: %@",
                                         error);abort();}
                               else {
                                   NSLog(@"Successfully added a migrated store: %@",
                                         _store);}
                               [self.migrationVC dismissViewControllerAnimated:NO
                                                                    completion:nil];
                               self.migrationVC = nil;
                           });
                       }
                   });
}

#pragma mark - VALIDATION ERROR HANDLING
- (void)showValidationError:(NSError *)anError {

    if (anError &amp;&amp; [anError.domain isEqualToString:@"NSCocoaErrorDomain"]) {
        NSArray *errors = nil;  // holds all errors
        NSString *txt = @""; // the error message text of the alert

        // Populate array with error(s)
        if (anError.code == NSValidationMultipleErrorsError) {
            errors = [anError.userInfo objectForKey:NSDetailedErrorsKey];
        } else {
            errors = [NSArray arrayWithObject:anError];
        }
        // Display the error(s)
        if (errors &amp;&amp; errors.count &gt; 0) {
            // Build error message text based on errors
            for (NSError * error in errors) {
                NSString *entity =
                [[[error.userInfo objectForKey:@"NSValidationErrorObject"]entity]name];

                NSString *property =
                [error.userInfo objectForKey:@"NSValidationErrorKey"];

                switch (error.code) {
                    case NSValidationRelationshipDeniedDeleteError:
                        txt = [txt stringByAppendingFormat:
                               @"%@ delete was denied because there are associated %@\n(Error Code %li)\n\n", entity, property, (long)error.code];
                        break;
                    case NSValidationRelationshipLacksMinimumCountError:
                        txt = [txt stringByAppendingFormat:
                               @"the '%@' relationship count is too small (Code %li).", property, (long)error.code];
                        break;
                    case NSValidationRelationshipExceedsMaximumCountError:
                        txt = [txt stringByAppendingFormat:
                               @"the '%@' relationship count is too large (Code %li).", property, (long)error.code];
                        break;
                    case NSValidationMissingMandatoryPropertyError:
                        txt = [txt stringByAppendingFormat:
                               @"the '%@' property is missing (Code %li).", property, (long)error.code];
                        break;
                    case NSValidationNumberTooSmallError:
                        txt = [txt stringByAppendingFormat:
                               @"the '%@' number is too small (Code %li).", property, (long)error.code];
                        break;
                    case NSValidationNumberTooLargeError:
                        txt = [txt stringByAppendingFormat:
                               @"the '%@' number is too large (Code %li).", property, (long)error.code];
                        break;
                    case NSValidationDateTooSoonError:
                        txt = [txt stringByAppendingFormat:
                               @"the '%@' date is too soon (Code %li).", property, (long)error.code];
                        break;
                    case NSValidationDateTooLateError:
                        txt = [txt stringByAppendingFormat:
                               @"the '%@' date is too late (Code %li).", property, (long)error.code];
                        break;
                    case NSValidationInvalidDateError:
                        txt = [txt stringByAppendingFormat:
                               @"the '%@' date is invalid (Code %li).", property, (long)error.code];
                        break;
                    case NSValidationStringTooLongError:
                        txt = [txt stringByAppendingFormat:
                               @"the '%@' text is too long (Code %li).", property, (long)error.code];
                        break;
                    case NSValidationStringTooShortError:
                        txt = [txt stringByAppendingFormat:
                               @"the '%@' text is too short (Code %li).", property, (long)error.code];
                        break;
                    case NSValidationStringPatternMatchingError:
                        txt = [txt stringByAppendingFormat:
                               @"the '%@' text doesn't match the specified pattern (Code %li).", property, (long)error.code];
                        break;
                    case NSManagedObjectValidationError:
                        txt = [txt stringByAppendingFormat:
                               @"generated validation error (Code %li)", (long)error.code];
                        break;

                    default:
                        txt = [txt stringByAppendingFormat:
                               @"Unhandled error code %li in showValidationError method", (long)error.code];
                        break;
                }
            }
            // display error message txt message
            UIAlertView *alertView =
            [[UIAlertView alloc] initWithTitle:@"Validation Error"

                                       message:[NSString stringWithFormat:@"%@Please double-tap the home button and close this application by swiping the application screenshot upwards",txt]
                                      delegate:nil
                             cancelButtonTitle:nil
                             otherButtonTitles:nil];
            [alertView show];
        }
    }
}

#pragma mark – DATA IMPORT
- (BOOL)isDefaultDataAlreadyImportedForStoreWithURL:(NSURL*)url
                                             ofType:(NSString*)type {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    NSError *error;
    NSDictionary *dictionary =
    [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:type
                                                               URL:url
                                                             error:&amp;error];
    if (error) {
        NSLog(@"Error reading persistent store metadata: %@",
              error.localizedDescription);
    }
    else {
        NSNumber *defaultDataAlreadyImported =
        [dictionary valueForKey:@"DefaultDataImported"];
        if (![defaultDataAlreadyImported boolValue]) {
            NSLog(@"Default Data has NOT already been imported");
            return NO;
        }
    }
    if (debug==1) {NSLog(@"Default Data HAS already been imported");}
    return YES;
}
- (void)checkIfDefaultDataNeedsImporting {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (![self isDefaultDataAlreadyImportedForStoreWithURL:[self storeURL]
                                                    ofType:NSSQLiteStoreType]) {
        self.importAlertView =
        [[UIAlertView alloc] initWithTitle:@"Import Default Data?"
                                   message:@"If you've never used Grocery Dude before then some default data might help you understand how to use it. Tap 'Import' to import default data. Tap 'Cancel' to skip the import, especially if you've done this before on other devices."
                                  delegate:self
                         cancelButtonTitle:@"Cancel"
                         otherButtonTitles:@"Import", nil];
        [self.importAlertView show];
    }
}
- (void)importFromXML:(NSURL*)url {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    self.parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
    self.parser.delegate = self;

    NSLog(@"**** START PARSE OF %@", url.path);
    [self.parser parse];
    [[NSNotificationCenter defaultCenter]
     postNotificationName:@"SomethingChanged" object:nil];
    NSLog(@"***** END PARSE OF %@", url.path);
}
- (void)setDefaultDataAsImportedForStore:(NSPersistentStore*)aStore {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    // get metadata dictionary
    NSMutableDictionary *dictionary =
    [NSMutableDictionary dictionaryWithDictionary:[[aStore metadata] copy]];

    if (debug==1) {
        NSLog(@"__Store Metadata BEFORE changes__ \n %@", dictionary);
    }

    // edit metadata dictionary
    [dictionary setObject:@YES forKey:@"DefaultDataImported"];

    // set metadata dictionary
    [self.coordinator setMetadata:dictionary forPersistentStore:aStore];

    if (debug==1) {NSLog(@"__Store Metadata AFTER changes__ \n %@", dictionary);}
}
- (void)setDefaultDataStoreAsInitialStore {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath:self.storeURL.path]) {
        NSURL *defaultDataURL =
        [NSURL fileURLWithPath:[[NSBundle mainBundle]
                                pathForResource:@"DefaultData" ofType:@"sqlite"]];
        NSError *error;
        if (![fileManager copyItemAtURL:defaultDataURL
                                  toURL:self.storeURL
                                  error:&amp;error]) {
            NSLog(@"DefaultData.sqlite copy FAIL: %@",
                  error.localizedDescription);
        }
        else {
            NSLog(@"A copy of DefaultData.sqlite was set as the initial store for %@",
                  self.storeURL.path);
        }
    }
}
- (void)deepCopyFromPersistentStore:(NSURL*)url {
    if (debug==1) {
        NSLog(@"Running %@ '%@' %@", self.class,
              NSStringFromSelector(_cmd),url.path);
    }
    // Periodically refresh the interface during the import
    _importTimer =
    [NSTimer scheduledTimerWithTimeInterval:2.0
                                     target:self
                                   selector:@selector(somethingChanged)
                                   userInfo:nil
                                    repeats:YES];

    [_sourceContext performBlock:^{

        NSLog(@"*** STARTED DEEP COPY FROM DEFAULT DATA PERSISTENT STORE ***");

        NSArray *entitiesToCopy = [NSArray arrayWithObjects:
                                   @"LocationAtHome",@"LocationAtShop",@"Unit",@"Item", nil];

        CoreDataImporter *importer = [[CoreDataImporter alloc]
                                      initWithUniqueAttributes:[self selectedUniqueAttributes]];

        [importer deepCopyEntities:entitiesToCopy
                       fromContext:_sourceContext
                         toContext:_importContext];

        [_context performBlock:^{
            // Stop periodically refreshing the interface
            [_importTimer invalidate];

            // Tell the interface to refresh once import completes
            [self somethingChanged];
        }];

        NSLog(@"*** FINISHED DEEP COPY FROM DEFAULT DATA PERSISTENT STORE ***");
    }];
}

#pragma mark – TEST DATA IMPORT (This code is Grocery Dude data specific)
- (void)importGroceryDudeTestData {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    NSNumber *imported =
    [[NSUserDefaults standardUserDefaults] objectForKey:@"TestDataImport"];

    if (!imported.boolValue) {
        NSLog(@"Importing test data...");
        [_importContext performBlock:^{

            NSManagedObject *locationAtHome =
            [NSEntityDescription insertNewObjectForEntityForName:@"LocationAtHome"
                                          inManagedObjectContext:_importContext];
            NSManagedObject *locationAtShop =
            [NSEntityDescription insertNewObjectForEntityForName:@"LocationAtShop"
                                          inManagedObjectContext:_importContext];
            [locationAtHome setValue:@"Test Home Location" forKey:@"storedIn"];
            [locationAtShop setValue:@"Test Shop Location" forKey:@"aisle"];

            for (int a = 1; a &lt; 101; a++) {                                  @autoreleasepool {                                          // Insert Item                     NSManagedObject *item =                     [NSEntityDescription insertNewObjectForEntityForName:@"Item"                                                   inManagedObjectContext:_importContext];                     [item setValue:[NSString stringWithFormat:@"Test Item %i",a]                             forKey:@"name"];                     [item setValue:locationAtHome                             forKey:@"locationAtHome"];                     [item setValue:locationAtShop                             forKey:@"locationAtShop"];                                          // Insert Photo                     NSManagedObject *photo =                     [NSEntityDescription insertNewObjectForEntityForName:@"Item_Photo"                                                   inManagedObjectContext:_importContext];                     [photo setValue:UIImagePNGRepresentation(                                                              [UIImage imageNamed:@"GroceryHead.png"])                              forKey:@"data"];                                          // Relate Item and Photo                     [item setValue:photo forKey:@"photo"];                                          NSLog(@"Inserting %@", [item valueForKey:@"name"]);                     [Faulter faultObjectWithID:photo.objectID                                      inContext:_importContext];                     [Faulter faultObjectWithID:item.objectID                                      inContext:_importContext];                 }             }             [_importContext reset];                          // ensure import was a one off             [[NSUserDefaults standardUserDefaults]              setObject:[NSNumber numberWithBool:YES]              forKey:@"TestDataImport"];             [[NSUserDefaults standardUserDefaults] synchronize];         }];     }     else {         NSLog(@"Skipped test data import");     } } #pragma mark - DELEGATE: UIAlertView - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {     if (debug==1) {         NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));     }     if (alertView == self.importAlertView) {         if (buttonIndex == 1) { // The ‘Import’ button on the importAlertView                          NSLog(@"Default Data Import Approved by User");             // XML Import             [_importContext performBlock:^{                 [self importFromXML:[[NSBundle mainBundle]                                      URLForResource:@"DefaultData"                                      withExtension:@"xml"]];             }];             // Deep Copy Import From Persistent Store             //[self loadSourceStore];             //[self deepCopyFromPersistentStore:[self sourceStoreURL]];                      } else {             NSLog(@"Default Data Import Cancelled by User");         }         // Set the data as imported regardless of the user's decision         [self setDefaultDataAsImportedForStore:_store];     } } #pragma mark - UNIQUE ATTRIBUTE SELECTION (This code is Grocery Dude data specific and is used when instantiating CoreDataImporter) - (NSDictionary*)selectedUniqueAttributes {     if (debug==1) {         NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));     }     NSMutableArray *entities   = [NSMutableArray new];     NSMutableArray *attributes = [NSMutableArray new];          // Select an attribute in each entity for uniqueness     [entities addObject:@"Item"];[attributes addObject:@"name"];     [entities addObject:@"Unit"];[attributes addObject:@"name"];     [entities addObject:@"LocationAtHome"];[attributes addObject:@"storedIn"];     [entities addObject:@"LocationAtShop"];[attributes addObject:@"aisle"];     [entities addObject:@"Item_Photo"];[attributes addObject:@"data"];          NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:attributes                                                            forKeys:entities];     return dictionary; } #pragma mark - DELEGATE: NSXMLParser (This code is Grocery Dude data specific) - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {     if (debug==1) {         NSLog(@"Parser Error: %@", parseError.localizedDescription);     } } - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName   namespaceURI:(NSString *)namespaceURI  qualifiedName:(NSString *)qName     attributes:(NSDictionary *)attributeDict {          [self.importContext performBlockAndWait:^{                  // STEP 1: Process only the 'item' element in the XML file         if ([elementName isEqualToString:@"item"]) {                          // STEP 2: Prepare the Core Data Importer             CoreDataImporter *importer =             [[CoreDataImporter alloc] initWithUniqueAttributes:              [self selectedUniqueAttributes]];                          // STEP 3a: Insert a unique 'Item' object             NSManagedObject *item =             [importer insertBasicObjectInTargetEntity:@"Item"                                 targetEntityAttribute:@"name"                                    sourceXMLAttribute:@"name"                                         attributeDict:attributeDict                                               context:_importContext];                          // STEP 3b: Insert a unique 'Unit' object             NSManagedObject *unit =             [importer insertBasicObjectInTargetEntity:@"Unit"                                 targetEntityAttribute:@"name"                                    sourceXMLAttribute:@"unit"                                         attributeDict:attributeDict                                               context:_importContext];                          // STEP 3c: Insert a unique 'LocationAtHome' object             NSManagedObject *locationAtHome =             [importer insertBasicObjectInTargetEntity:@"LocationAtHome"                                 targetEntityAttribute:@"storedIn"                                    sourceXMLAttribute:@"locationathome"                                         attributeDict:attributeDict                                               context:_importContext];                          // STEP 3d: Insert a unique 'LocationAtShop' object             NSManagedObject *locationAtShop =             [importer insertBasicObjectInTargetEntity:@"LocationAtShop"                                 targetEntityAttribute:@"aisle"                                    sourceXMLAttribute:@"locationatshop"                                         attributeDict:attributeDict                                               context:_importContext];                          // STEP 4: Manually add extra attribute values.             [item setValue:@NO forKey:@"listed"];                          // STEP 5: Create relationships             [item setValue:unit forKey:@"unit"];             [item setValue:locationAtHome forKey:@"locationAtHome"];             [item setValue:locationAtShop forKey:@"locationAtShop"];                          // STEP 6: Save new objects to the persistent store.             [CoreDataImporter saveContext:_importContext];                          // STEP 7: Turn objects into faults to save memory             [Faulter faultObjectWithID:item.objectID inContext:_importContext];             [Faulter faultObjectWithID:unit.objectID inContext:_importContext];             [Faulter faultObjectWithID:locationAtHome.objectID inContext:_importContext];             [Faulter faultObjectWithID:locationAtShop.objectID inContext:_importContext];         }     }]; } #pragma mark – UNDERLYING DATA CHANGE NOTIFICATION - (void)somethingChanged {     if (debug==1) {         NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));     }     // Send a notification that tells observing interfaces to refresh their data     [[NSNotificationCenter defaultCenter]      postNotificationName:@"SomethingChanged" object:nil]; } #pragma mark - CORE DATA RESET - (void)resetContext:(NSManagedObjectContext*)moc {     [moc performBlockAndWait:^{         [moc reset];     }]; } - (BOOL)reloadStore {     BOOL success = NO;     NSError *error = nil;     if (![_coordinator removePersistentStore:_store error:&amp;error]) {         NSLog(@"Unable to remove persistent store : %@", error);     }     [self resetContext:_sourceContext];     [self resetContext:_importContext];     [self resetContext:_context];     [self resetContext:_parentContext];     _store = nil;     [self setupCoreData];     [self somethingChanged];     if (_store) {success = YES;}     return success; } - (void)removeAllStoresFromCoordinator:(NSPersistentStoreCoordinator*)psc {     if (debug==1) {         NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));     }     for (NSPersistentStore *s in psc.persistentStores) {         NSError *error = nil;         if (![psc removePersistentStore:s error:&amp;error]) {             NSLog(@"Error removing persistent store: %@", error);         }     } } - (void)resetCoreData {     if (debug==1) {         NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));     }     [_importContext performBlockAndWait:^{         [_importContext save:nil];         [self resetContext:_importContext];     }];     [_context performBlockAndWait:^{         [_context save:nil];         [self resetContext:_context];     }];     [_parentContext performBlockAndWait:^{         [_parentContext save:nil];         [self resetContext:_parentContext];     }];     [self removeAllStoresFromCoordinator:_coordinator];     _store = nil;     _iCloudStore = nil; } #pragma mark - ICLOUD - (BOOL)iCloudAccountIsSignedIn {     if (debug==1) {         NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));     }     id token = [[NSFileManager defaultManager] ubiquityIdentityToken];     if (token) {         NSLog(@"** iCloud is SIGNED IN with token '%@' **", token);         return YES;     }     NSLog(@"** iCloud is NOT SIGNED IN **");     NSLog(@"--&gt; Is iCloud Documents and Data enabled for a valid iCloud account on your Mac &amp; iOS Device or iOS Simulator?");
    NSLog(@"--&gt; Have you enabled the iCloud Capability in the Application Target?");
    NSLog(@"--&gt; Is there a CODE_SIGN_ENTITLEMENTS Xcode warning that needs fixing? You may need to specifically choose a developer instead of using Automatic selection");
    NSLog(@"--&gt; Are you using a Pre-iOS7 Simulator?");
    return NO;
}
- (BOOL)loadiCloudStore {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (_iCloudStore) {return YES;} // Don’t load iCloud store if it’s already loaded

    NSDictionary *options =
    @{
      NSMigratePersistentStoresAutomaticallyOption:@YES
      ,NSInferMappingModelAutomaticallyOption:@YES
      ,NSPersistentStoreUbiquitousContentNameKey:@"Grocery-Dude"
      //,NSPersistentStoreUbiquitousContentURLKey:@"ChangeLogs" // Optional since iOS7
      };
    NSError *error;
    _iCloudStore = [_coordinator addPersistentStoreWithType:NSSQLiteStoreType
                                              configuration:nil
                                                        URL:[self iCloudStoreURL]
                                                    options:options
                                                      error:&amp;error];
    if (_iCloudStore) {
        NSLog(@"** The iCloud Store has been successfully configured at '%@' **",
              _iCloudStore.URL.path);
        return YES;
    }
    NSLog(@"** FAILED to configure the iCloud Store : %@ **", error);
    return NO;
}
- (void)listenForStoreChanges {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    NSNotificationCenter *dc = [NSNotificationCenter defaultCenter];
    [dc addObserver:self
           selector:@selector(storesWillChange:)
               name:NSPersistentStoreCoordinatorStoresWillChangeNotification
             object:_coordinator];

    [dc addObserver:self
           selector:@selector(storesDidChange:)
               name:NSPersistentStoreCoordinatorStoresDidChangeNotification
             object:_coordinator];

    [dc addObserver:self
           selector:@selector(persistentStoreDidImportUbiquitiousContentChanges:)
               name:NSPersistentStoreDidImportUbiquitousContentChangesNotification
             object:_coordinator];
}
- (void)storesWillChange:(NSNotification *)n {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [_importContext performBlockAndWait:^{
        [_importContext save:nil];
        [self resetContext:_importContext];
    }];
    [_context performBlockAndWait:^{
        [_context save:nil];
        [self resetContext:_context];
    }];
    [_parentContext performBlockAndWait:^{
        [_parentContext save:nil];
        [self resetContext:_parentContext];
    }];

    // Refresh UI
    [[NSNotificationCenter defaultCenter] postNotificationName:@"SomethingChanged"
                                                        object:nil
                                                      userInfo:nil];
}
- (void)storesDidChange:(NSNotification *)n {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    // Refresh UI
    [[NSNotificationCenter defaultCenter] postNotificationName:@"SomethingChanged"
                                                        object:nil
                                                      userInfo:nil];
}
- (void)persistentStoreDidImportUbiquitiousContentChanges:(NSNotification*)n {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [_context performBlock:^{
        [_context mergeChangesFromContextDidSaveNotification:n];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"SomethingChanged"
                                                            object:nil];
    }];
}
- (BOOL)iCloudEnabledByUser {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [[NSUserDefaults standardUserDefaults] synchronize]; // Ensure current value
    if ([[[NSUserDefaults standardUserDefaults]
          objectForKey:@"iCloudEnabled"] boolValue]) {
        NSLog(@"** iCloud is ENABLED in Settings **");
        return YES;
    }
    NSLog(@"** iCloud is DISABLED in Settings **");
    return NO;
}
- (void)ensureAppropriateStoreIsLoaded {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (!_store &amp;&amp; !_iCloudStore) {
        return; // If neither store is loaded, skip (usually first launch)
    }
    if (![self iCloudEnabledByUser] &amp;&amp; _store) {
        NSLog(@"The Non-iCloud Store is loaded as it should be");
        return;
    }
    if ([self iCloudEnabledByUser] &amp;&amp; _iCloudStore) {
        NSLog(@"The iCloud Store is loaded as it should be");
        return;
    }
    NSLog(@"** The user preference on using iCloud with this application appears to have changed. Core Data will now be reset. **");

    [self resetCoreData];
    [self setupCoreData];

    [[NSNotificationCenter defaultCenter] postNotificationName:@"SomethingChanged"
                                                        object:nil];

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:
                          @"Your preference on using iCloud with this application appears to have changed"
                                                    message:
                          @"Content has been updated accordingly"
                                                   delegate:nil
                                          cancelButtonTitle:nil
                                          otherButtonTitles:@"Ok", nil];
    [alert show];
}

@end

 

CoreDataTVC.h

#import <UIKit/UIKit.h>
#import "CoreDataHelper.h"
@interface CoreDataTVC : UITableViewController
<NSFetchedResultsControllerDelegate, UISearchBarDelegate, UISearchDisplayDelegate>
@property (strong, nonatomic) NSFetchedResultsController *frc;
@property (strong, nonatomic) NSFetchedResultsController *searchFRC;
@property (strong, nonatomic) UISearchDisplayController *searchDC;
- (void)performFetch;
- (NSFetchedResultsController*)frcFromTV:(UITableView*)tableView;
- (UITableView*)TVFromFRC:(NSFetchedResultsController*)frc;
- (void)reloadSearchFRCForPredicate:(NSPredicate*)predicate
                         withEntity:(NSString*)entity
                          inContext:(NSManagedObjectContext*)context
                withSortDescriptors:(NSArray*)sortDescriptors
             withSectionNameKeyPath:(NSString*)sectionNameKeyPath;
- (void)configureSearch;
@end

#import "CoreDataTVC.h"
@implementation CoreDataTVC
#define debug 0

#pragma mark - FETCHING
- (void)performFetch {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    
    if (self.frc) {
        [self.frc.managedObjectContext performBlockAndWait:^{
            
            NSError *error = nil;
            if (![self.frc performFetch:&error]) {
                
                NSLog(@"Failed to perform fetch: %@", error);
            }
            [self.tableView reloadData];
        }];
    } else {
        NSLog(@"Failed to fetch, the fetched results controller is nil.");
    }
}

#pragma mark - DATASOURCE: UITableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    return [[[[self frcFromTV:tableView]sections]
             objectAtIndex:section] numberOfObjects];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    return [[[self frcFromTV:tableView] sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    return [[self frcFromTV:tableView]
            sectionForSectionIndexTitle:title atIndex:index];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    return [[[[self frcFromTV:tableView] sections] objectAtIndex:section] name];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    return [[self frcFromTV:tableView] sectionIndexTitles];
}

#pragma mark - DELEGATE: NSFetchedResultsController
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [[self TVFromFRC:controller] beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [[self TVFromFRC:controller] endUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller
  didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex
     forChangeType:(NSFetchedResultsChangeType)type {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [[self TVFromFRC:controller]
             insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
             withRowAnimation:UITableViewRowAnimationFade];
            break;
            
        case NSFetchedResultsChangeDelete:
            [[self TVFromFRC:controller]
             deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
             withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}
- (void)controller:(NSFetchedResultsController *)controller
   didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath
     forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    
    switch(type) {
            
        case NSFetchedResultsChangeInsert:
            [[self TVFromFRC:controller]
             insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
             withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
            
        case NSFetchedResultsChangeDelete:
            [[self TVFromFRC:controller]
             deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
             withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
            
        case NSFetchedResultsChangeUpdate:
            if (!newIndexPath) {
                [[self TVFromFRC:controller]
                 reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                 withRowAnimation:UITableViewRowAnimationNone];
            }
            else {
                [[self TVFromFRC:controller]
                 deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                 withRowAnimation:UITableViewRowAnimationNone];
                [[self TVFromFRC:controller]
                 insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                 withRowAnimation:UITableViewRowAnimationNone];
            }
            break;
            
        case NSFetchedResultsChangeMove:
            [[self TVFromFRC:controller]
             deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
             withRowAnimation:UITableViewRowAnimationAutomatic];
            [[self TVFromFRC:controller]
             insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
             withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
    }
}

#pragma mark - GENERAL
- (NSFetchedResultsController*)frcFromTV:(UITableView*)tableView {
    /*
     If the given tableView is self.tableView return self.frc,
     otherwise self.searchFRC
     */
    return (tableView == self.tableView) ? self.frc : self.searchFRC;
}
- (UITableView*)TVFromFRC:(NSFetchedResultsController*)frc {
    /*
     If the given fetched results controller is self.frc return self.tableView,
     otherwise self.searchDC.searchResultsTableView
     */
    return (frc == self.frc) ? self.tableView : self.searchDC.searchResultsTableView;
}

#pragma mark - DELEGATE: UISearchDisplayController
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    self.searchFRC.delegate = nil;
    self.searchFRC = nil;
}

#pragma mark - SEARCH
- (void)reloadSearchFRCForPredicate:(NSPredicate*)predicate
                         withEntity:(NSString*)entity
                          inContext:(NSManagedObjectContext*)context
                withSortDescriptors:(NSArray*)sortDescriptors
             withSectionNameKeyPath:(NSString*)sectionNameKeyPath {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:entity];
    request.sortDescriptors = sortDescriptors;
    request.predicate = predicate;
    request.fetchBatchSize = 15;
    
    self.searchFRC =
    [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                        managedObjectContext:context
                                          sectionNameKeyPath:sectionNameKeyPath
                                                   cacheName:nil];
    self.searchFRC.delegate = self;
    
    [self.searchFRC.managedObjectContext performBlockAndWait:^{
        NSError *error;
        if (![self.searchFRC performFetch:&error]) {
            NSLog(@"SEARCH FETCH ERROR: %@", error);
        }
    }];
}
- (void)configureSearch {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    UISearchBar *searchBar =
    [[UISearchBar alloc] initWithFrame:
     CGRectMake(0, 0, self.tableView.frame.size.width, 44.0)];
    searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
    self.tableView.tableHeaderView = searchBar;
    
    self.searchDC =
    [[UISearchDisplayController alloc] initWithSearchBar:searchBar
                                      contentsController:self];
    self.searchDC.delegate = self;
    self.searchDC.searchResultsDataSource = self;
    self.searchDC.searchResultsDelegate = self;
}

@end

说明:

1.获取objectID unitVC.selectedObjectID =[[self.frc objectAtIndexPath:indexPath] objectID];

2.传递的是objectID,通过[cdh.context existingObjectWithID:self.selectedObjectIDerror:nil] 获取该object;

itemtvc

vc

PrepareTVC

#import &lt;UIKit/UIKit.h&gt;
#import "CoreDataTVC.h"
@interface PrepareTVC : CoreDataTVC 
@property (strong, nonatomic) UIActionSheet *clearConfirmActionSheet;
@end

#import "PrepareTVC.h"
#import "CoreDataHelper.h"
#import "Item.h"
#import "Unit.h"
#import "AppDelegate.h"
#import "ItemVC.h"
#import "Thumbnailer.h"

@implementation PrepareTVC
#define debug 0

#pragma mark - DATA
- (void)configureFetch {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    CoreDataHelper *cdh =
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];

    NSFetchRequest *request =
    [NSFetchRequest fetchRequestWithEntityName:@"Item"];

    request.sortDescriptors =
    [NSArray arrayWithObjects:
     [NSSortDescriptor sortDescriptorWithKey:@"locationAtHome.storedIn"
                                   ascending:YES],
     [NSSortDescriptor sortDescriptorWithKey:@"name"
                                   ascending:YES],
     nil];
    [request setFetchBatchSize:15];
    self.frc =
    [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                        managedObjectContext:cdh.context
                                          sectionNameKeyPath:@"locationAtHome.storedIn"
                                                   cacheName:nil];
    self.frc.delegate = self;
}

#pragma mark - VIEW
- (void)viewDidAppear:(BOOL)animated {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [super viewDidAppear:animated];

    // Create missing Thumbnails
    CoreDataHelper *cdh =
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
    NSArray *sortDescriptors =
    [NSArray arrayWithObjects:
     [NSSortDescriptor sortDescriptorWithKey:@"locationAtHome.storedIn"
                                   ascending:YES],
     [NSSortDescriptor sortDescriptorWithKey:@"name"
                                   ascending:YES],
     nil];

    [Thumbnailer createMissingThumbnailsForEntityName:@"Item"
                           withThumbnailAttributeName:@"thumbnail"
                            withPhotoRelationshipName:@"photo"
                               withPhotoAttributeName:@"data"
                                  withSortDescriptors:sortDescriptors
                                    withImportContext:cdh.importContext];
}
- (void)viewDidLoad {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [super viewDidLoad];
    [self configureFetch];
    [self performFetch];
    self.clearConfirmActionSheet.delegate = self;

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(performFetch)
                                                 name:@"SomethingChanged"
                                               object:nil];
    [self configureSearch];
}
- (UITableViewCell*)tableView:(UITableView *)tableView
        cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    static NSString *cellIdentifier = @"Item Cell";

    UITableViewCell *cell =
    [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
                                      reuseIdentifier:cellIdentifier];
    }
    cell.accessoryType = UITableViewCellAccessoryDetailButton;
    Item *item = [[self frcFromTV:tableView] objectAtIndexPath:indexPath];

    NSMutableString *title = [NSMutableString stringWithFormat:@"%@%@ %@",
                              item.quantity, item.unit.name, item.name];
    [title replaceOccurrencesOfString:@"(null)"
                           withString:@""
                              options:0
                                range:NSMakeRange(0, [title length])];
    cell.textLabel.text = title;

    // make selected items orange
    if ([item.listed boolValue]) {
        [cell.textLabel setFont:[UIFont fontWithName:@"Helvetica Neue" size:18]];
        [cell.textLabel setTextColor:[UIColor orangeColor]];
    }
    else {
        [cell.textLabel setFont:[UIFont fontWithName:@"Helvetica Neue" size:16]];
        [cell.textLabel setTextColor:[UIColor grayColor]];
    }
    cell.imageView.image = [UIImage imageWithData:item.thumbnail];
    return cell;
}
- (NSArray*)sectionIndexTitlesForTableView:(UITableView *)tableView {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    return nil; // we don't want a section index.
}
- (void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (editingStyle == UITableViewCellEditingStyleDelete) {

        NSFetchedResultsController *frc = [self frcFromTV:tableView];
        Item *deleteTarget = [frc objectAtIndexPath:indexPath];
        [frc.managedObjectContext deleteObject:deleteTarget];
        [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                         withRowAnimation:UITableViewRowAnimationFade];
    }
    CoreDataHelper *cdh =
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
    [cdh backgroundSaveContext];
}
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath  {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    NSFetchedResultsController *frc = [self frcFromTV:tableView];
    NSManagedObjectID *itemid = [[frc objectAtIndexPath:indexPath] objectID];

    Item *item =
    (Item*)[frc.managedObjectContext existingObjectWithID:itemid error:nil];
    if ([item.listed boolValue]) {
        item.listed = [NSNumber numberWithBool:NO];
    }
    else {
        item.listed = [NSNumber numberWithBool:YES];
        item.collected = [NSNumber numberWithBool:NO];
    }
    CoreDataHelper *cdh =
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
    [cdh backgroundSaveContext];
}

#pragma mark - INTERACTION
- (IBAction)clear:(id)sender {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }

    CoreDataHelper *cdh =
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
    NSFetchRequest *request =
    [cdh.model fetchRequestTemplateForName:@"ShoppingList"];
    NSArray *shoppingList =
    [cdh.context executeFetchRequest:request error:nil];

    if (shoppingList.count &gt; 0) {

        self.clearConfirmActionSheet =
        [[UIActionSheet alloc] initWithTitle:@"Clear Entire Shopping List?"
                                    delegate:self
                           cancelButtonTitle:@"Cancel"
                      destructiveButtonTitle:@"Clear"
                           otherButtonTitles:nil];
        [self.clearConfirmActionSheet
         showFromTabBar:self.navigationController.tabBarController.tabBar];
    }
    else {
        UIAlertView *alert =
        [[UIAlertView alloc] initWithTitle:@"Nothing to Clear"
                                   message:@"Add items to the Shop tab by tapping them on the Prepare tab. Remove all items from the Shop tab by clicking Clear on the Prepare tab"
                                  delegate:nil
                         cancelButtonTitle:@"Ok"
                         otherButtonTitles:nil];
        [alert show];
    }
    shoppingList = nil;
    [cdh backgroundSaveContext];
}
- (void)actionSheet:(UIActionSheet *)actionSheet
clickedButtonAtIndex:(NSInteger)buttonIndex {

    if (actionSheet == self.clearConfirmActionSheet) {
        if (buttonIndex == [actionSheet destructiveButtonIndex]) {
            [self performSelector:@selector(clearList)];
        }
        else if (buttonIndex == [actionSheet cancelButtonIndex]){
            [actionSheet dismissWithClickedButtonIndex:
             [actionSheet cancelButtonIndex] animated:YES];
        }
    }
}
- (void)clearList {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }

    CoreDataHelper *cdh =
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
    NSFetchRequest *request =
    [cdh.model fetchRequestTemplateForName:@"ShoppingList"];
    NSArray *shoppingList =
    [cdh.context executeFetchRequest:request error:nil];

    for (Item *item in shoppingList) {
        item.listed = [NSNumber numberWithBool:NO];
    }
    [cdh backgroundSaveContext];
}

#pragma mark - SEGUE
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    ItemVC *itemVC = segue.destinationViewController;
    if ([segue.identifier isEqualToString:@"Add Item Segue"])
    {
        CoreDataHelper *cdh =
        [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
        Item *newItem =
        [NSEntityDescription insertNewObjectForEntityForName:@"Item"
                                      inManagedObjectContext:cdh.context];
        NSError *error = nil;
        if (![cdh.context
              obtainPermanentIDsForObjects:[NSArray arrayWithObject:newItem]
              error:&amp;error]) {
            NSLog(@"Couldn't obtain a permanent ID for object %@", error);
        }
        itemVC.selectedItemID = newItem.objectID;
    }
    else {
        NSLog(@"Unidentified Segue Attempted!");
    }
}
- (void)tableView:(UITableView *)tableView
accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    ItemVC *itemVC =
    [self.storyboard instantiateViewControllerWithIdentifier:@"ItemVC"];
    itemVC.selectedItemID =
    [[[self frcFromTV:tableView] objectAtIndexPath:indexPath] objectID];
    [self.navigationController pushViewController:itemVC animated:YES];
}

#pragma mark - SEARCH
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (searchString.length &gt; 0) {
        NSLog(@"--&gt; Searching for '%@'", searchString);
        NSPredicate *predicate =
        [NSPredicate predicateWithFormat:@"name CONTAINS[cd] %@", searchString];

        NSArray *sortDescriptors =
        [NSArray arrayWithObjects:
         [NSSortDescriptor sortDescriptorWithKey:@"locationAtHome.storedIn"
                                       ascending:YES],
         [NSSortDescriptor sortDescriptorWithKey:@"name"
                                       ascending:YES], nil];

        CoreDataHelper *cdh =
        [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];

        [self reloadSearchFRCForPredicate:predicate
                               withEntity:@"Item"
                                inContext:cdh.context
                      withSortDescriptors:sortDescriptors
                   withSectionNameKeyPath:@"locationAtHome.storedIn"];
    } else {
        return NO;
    }
    return YES;
}
@end

ShopTVC.m

#import "ShopTVC.h"
#import "CoreDataHelper.h"
#import "Item.h"
#import "Unit.h"
#import "AppDelegate.h"
#import "ItemVC.h"
#import "Thumbnailer.h"

@implementation ShopTVC
#define debug 0

#pragma mark - DATA
- (void)configureFetch {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    CoreDataHelper *cdh =
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
    NSFetchRequest *request =
    [[cdh.model fetchRequestTemplateForName:@"ShoppingList"] copy];

    request.sortDescriptors =
    [NSArray arrayWithObjects:
     [NSSortDescriptor sortDescriptorWithKey:@"locationAtShop.aisle"
                                   ascending:YES],
     [NSSortDescriptor sortDescriptorWithKey:@"name"
                                   ascending:YES],
     nil];
    [request setFetchBatchSize:15];

    self.frc =
    [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                        managedObjectContext:cdh.context
                                          sectionNameKeyPath:@"locationAtShop.aisle"
                                                   cacheName:nil];
    self.frc.delegate = self;
}

#pragma mark - VIEW
- (void)viewDidAppear:(BOOL)animated {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [super viewDidAppear:animated];

    // Create missing Thumbnails
    CoreDataHelper *cdh =
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
    NSArray *sortDescriptors =
    [NSArray arrayWithObjects:
     [NSSortDescriptor sortDescriptorWithKey:@"locationAtHome.storedIn"
                                   ascending:YES],
     [NSSortDescriptor sortDescriptorWithKey:@"name"
                                   ascending:YES],
     nil];

    [Thumbnailer createMissingThumbnailsForEntityName:@"Item"
                           withThumbnailAttributeName:@"thumbnail"
                            withPhotoRelationshipName:@"photo"
                               withPhotoAttributeName:@"data"
                                  withSortDescriptors:sortDescriptors
                                    withImportContext:cdh.importContext];
}
- (void)viewDidLoad {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [super viewDidLoad];
    [self configureFetch];
    [self performFetch];

    // Respond to changes in underlying store
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(performFetch)
                                                 name:@"SomethingChanged"
                                               object:nil];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    static NSString *cellIdentifier = @"Shop Cell";
    UITableViewCell *cell =
    [tableView dequeueReusableCellWithIdentifier:cellIdentifier
                                    forIndexPath:indexPath];

    Item *item = [self.frc objectAtIndexPath:indexPath];
    NSMutableString *title = [NSMutableString stringWithFormat:@"%@%@ %@",
                              item.quantity, item.unit.name, item.name];
    [title replaceOccurrencesOfString:@"(null)"
                           withString:@""
                              options:0
                                range:NSMakeRange(0, [title length])];
    cell.textLabel.text = title;

    // make collected items green
    if (item.collected.boolValue) {
        [cell.textLabel setFont:[UIFont
                                 fontWithName:@"Helvetica Neue" size:16]];
        [cell.textLabel setTextColor:
         [UIColor colorWithRed:0.368627450
                         green:0.741176470
                          blue:0.349019607 alpha:1.0]];
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    }
    else {
        [cell.textLabel setFont:[UIFont
                                 fontWithName:@"Helvetica Neue" size:18]];
        cell.textLabel.textColor = [UIColor orangeColor];
        cell.accessoryType = UITableViewCellAccessoryDetailButton;
    }

    cell.imageView.image = [UIImage imageWithData:item.thumbnail];

    return cell;
}
- (NSArray*)sectionIndexTitlesForTableView:(UITableView *)tableView {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    return nil; // prevent section index.
}
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath  {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    Item *item = [self.frc objectAtIndexPath:indexPath];
    if (item.collected.boolValue) {
        item.collected = [NSNumber numberWithBool:NO];
    }
    else {
        item.collected = [NSNumber numberWithBool:YES];
    }
    [self.tableView reloadRowsAtIndexPaths:
     [NSArray  arrayWithObject:indexPath]
                          withRowAnimation:UITableViewRowAnimationNone];

    CoreDataHelper *cdh = [(AppDelegate *)[[UIApplication
                                            sharedApplication] delegate] cdh];
    [cdh backgroundSaveContext];
}

#pragma mark - INTERACTION
- (IBAction)clear:(id)sender {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if ([self.frc.fetchedObjects count] == 0) {

        UIAlertView *alert =
        [[UIAlertView alloc] initWithTitle:@"Nothing to Clear"
                                   message:@"Add items using the Prepare tab"
                                  delegate:nil
                         cancelButtonTitle:@"Ok" otherButtonTitles:nil];
        [alert show];
        return;
    }
    BOOL nothingCleared = YES;
    for (Item *item in self.frc.fetchedObjects) {

        if (item.collected.boolValue)
        {
            item.listed = [NSNumber numberWithBool:NO];
            item.collected = [NSNumber numberWithBool:NO];
            nothingCleared = NO;
        }
    }
    if (nothingCleared) {
        UIAlertView *alert =
        [[UIAlertView alloc] initWithTitle:nil message:
         @"Select items to be removed from the list before pressing Clear"
                                  delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
        [alert show];
    }
    CoreDataHelper *cdh = [(AppDelegate *)[[UIApplication
                                            sharedApplication] delegate] cdh];
    [cdh backgroundSaveContext];
}

#pragma mark - SEGUE
- (void)tableView:(UITableView *)tableView
accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    ItemVC *itemVC =
    [self.storyboard instantiateViewControllerWithIdentifier:@"ItemVC"];
    itemVC.selectedItemID =
    [[self.frc objectAtIndexPath:indexPath] objectID];
    [self.navigationController pushViewController:itemVC animated:YES];
}
@end

ItemVC

itemVC

#import &lt;UIKit/UIKit.h&gt;
#import "CoreDataHelper.h"
#import "UnitPickerTF.h"
#import "LocationAtHomePickerTF.h" 
#import "LocationAtShopPickerTF.h"

@interface ItemVC : UIViewController &lt;UITextFieldDelegate,CoreDataPickerTFDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate&gt;
@property (strong, nonatomic) NSManagedObjectID *selectedItemID;
@property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
@property (strong, nonatomic) IBOutlet UITextField *nameTextField;
@property (strong, nonatomic) IBOutlet UITextField *quantityTextField;
@property (strong, nonatomic) IBOutlet UnitPickerTF *unitPickerTextField;
@property (strong, nonatomic) IBOutlet LocationAtHomePickerTF *homeLocationPickerTextField;
@property (strong, nonatomic) IBOutlet LocationAtShopPickerTF *shopLocationPickerTextField;
@property (strong, nonatomic) IBOutlet UITextField *activeField;
@property (strong, nonatomic) IBOutlet UIImageView *photoImageView;
@property (strong, nonatomic) IBOutlet UIButton *cameraButton;
@property (strong, nonatomic) UIImagePickerController *camera;
@end

ItemVC

#import "ItemVC.h"
#import "AppDelegate.h" 
#import "Item.h"
#import "LocationAtHome.h"
#import "LocationAtShop.h"
#import "Unit.h"
#import "Item_Photo.h"

@implementation ItemVC
#define debug 0

#pragma mark - INTERACTION
- (IBAction)done:(id)sender {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [self hideKeyboard];
    [self.navigationController popViewControllerAnimated:YES];
}
- (void)hideKeyboardWhenBackgroundIsTapped {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    UITapGestureRecognizer *tgr =
    [[UITapGestureRecognizer alloc] initWithTarget:self
                                            action:@selector(hideKeyboard)];
    [tgr setCancelsTouchesInView:NO];
    [self.view addGestureRecognizer:tgr];
}
- (void)hideKeyboard {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [self.view endEditing:YES];
}
- (void)keyboardDidShow:(NSNotification *)n {

    // Find top of keyboard input view (i.e. picker)
    CGRect keyboardRect =
    [[[n userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    keyboardRect = [self.view convertRect:keyboardRect fromView:nil];
    CGFloat keyboardTop = keyboardRect.origin.y;

    // Resize scroll view
    CGRect newScrollViewFrame =
    CGRectMake(0, 0, self.view.bounds.size.width, keyboardTop);
    newScrollViewFrame.size.height = keyboardTop - self.view.bounds.origin.y;
    [self.scrollView setFrame:newScrollViewFrame];

    // Scroll to the active Text-Field
    [self.scrollView scrollRectToVisible:self.activeField.frame animated:YES];
}
- (void)keyboardWillHide:(NSNotification *)n {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    CGRect defaultFrame =
    CGRectMake(self.scrollView.frame.origin.x,
               self.scrollView.frame.origin.y,
               self.view.frame.size.width,
               self.view.frame.size.height);

    // Reset Scrollview to the same size as the containing view
    [self.scrollView setFrame:defaultFrame];

    // Scroll to the top again
    [self.scrollView scrollRectToVisible:self.nameTextField.frame
                                animated:YES];
}

#pragma mark - DELEGATE: UITextField
- (void)textFieldDidBeginEditing:(UITextField *)textField {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (textField == self.nameTextField) {

        if ([self.nameTextField.text isEqualToString:@"New Item"]) {
            self.nameTextField.text = @"";
        }
    }
    if (textField == _unitPickerTextField &amp;&amp; _unitPickerTextField.picker) {
        [_unitPickerTextField fetch];
        [_unitPickerTextField.picker reloadAllComponents];
    } else if (textField == _homeLocationPickerTextField &amp;&amp;
               _homeLocationPickerTextField.picker) {
        [_homeLocationPickerTextField fetch];
        [_homeLocationPickerTextField.picker reloadAllComponents];
    } else if (textField == _shopLocationPickerTextField &amp;&amp;
               _shopLocationPickerTextField.picker) {
        [_shopLocationPickerTextField fetch];
        [_shopLocationPickerTextField.picker reloadAllComponents];
    }
    _activeField = textField;
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    CoreDataHelper *cdh =
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
    Item *item =
    (Item*)[cdh.context existingObjectWithID:self.selectedItemID error:nil];

    if (textField == self.nameTextField) {
        if ([self.nameTextField.text isEqualToString:@""]) {
            self.nameTextField.text = @"New Item";
        }
        item.name = self.nameTextField.text;
    }
    else if (textField == self.quantityTextField) {
        item.quantity =
        [NSNumber numberWithFloat:self.quantityTextField.text.floatValue];
    }
}

#pragma mark - VIEW
- (void)refreshInterface {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (self.selectedItemID) {
        CoreDataHelper *cdh = [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
        Item *item = (Item*)[cdh.context existingObjectWithID:self.selectedItemID error:nil];
        self.nameTextField.text = item.name;
        self.quantityTextField.text = item.quantity.stringValue;
        self.unitPickerTextField.text = item.unit.name;
        self.unitPickerTextField.selectedObjectID = item.unit.objectID;
        self.homeLocationPickerTextField.text = item.locationAtHome.storedIn;
        self.homeLocationPickerTextField.selectedObjectID = item.locationAtHome.objectID;
        self.shopLocationPickerTextField.text = item.locationAtShop.aisle;
        self.shopLocationPickerTextField.selectedObjectID = item.locationAtShop.objectID;

        [cdh.context performBlock:^{
            self.photoImageView.image =
            [UIImage imageWithData:item.photo.data];
        }];

        [self checkCamera];
    }
}
- (void)viewDidLoad {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [super viewDidLoad];
    [self hideKeyboardWhenBackgroundIsTapped];
    self.nameTextField.delegate = self;
    self.quantityTextField.delegate = self;

    self.unitPickerTextField.delegate = self;
    self.unitPickerTextField.pickerDelegate = self;
    self.homeLocationPickerTextField.delegate = self;
    self.homeLocationPickerTextField.pickerDelegate = self;
    self.shopLocationPickerTextField.delegate = self;
    self.shopLocationPickerTextField.pickerDelegate = self;
}
- (void)viewWillAppear:(BOOL)animated {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }

    // Register for keyboard notifications while the view is visible.
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardDidShow:)
                                                 name:UIKeyboardDidShowNotification
                                               object:self.view.window];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillHide:)
                                                 name:UIKeyboardWillHideNotification
                                               object:self.view.window];

    [self ensureItemHomeLocationIsNotNull];
    [self ensureItemShopLocationIsNotNull];

    [self refreshInterface];
    if ([self.nameTextField.text isEqual:@"New Item"]) {
        self.nameTextField.text = @"";
        [self.nameTextField becomeFirstResponder];
    }
}
- (void)viewDidDisappear:(BOOL)animated {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [self ensureItemHomeLocationIsNotNull];
    [self ensureItemShopLocationIsNotNull];

    CoreDataHelper *cdh =
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
    [cdh backgroundSaveContext];

    // Unregister for keyboard notifications while the view is not visible.
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardDidShowNotification
                                                  object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillHideNotification
                                                  object:nil];

    // Turn item &amp; item photo into a fault
    NSError *error;
    Item *item =
    (Item*)[cdh.context existingObjectWithID:self.selectedItemID error:&amp;error];
    if (error) {
        NSLog(@"ERROR!!! --&gt; %@", error.localizedDescription);
    } else {
        [cdh.context refreshObject:item.photo mergeChanges:NO];
        [cdh.context refreshObject:item mergeChanges:NO];
    }
}

#pragma mark - DATA
- (void)ensureItemHomeLocationIsNotNull {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (self.selectedItemID) {
        CoreDataHelper *cdh =
        [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
        Item *item =
        (Item*)[cdh.context existingObjectWithID:self.selectedItemID
                                           error:nil];
        if (!item.locationAtHome) {
            NSFetchRequest *request =
            [[cdh model]
             fetchRequestTemplateForName:@"UnknownLocationAtHome"];
            NSArray *fetchedObjects =
            [cdh.context executeFetchRequest:request error:nil];

            if ([fetchedObjects count] &gt; 0) {
                item.locationAtHome = [fetchedObjects objectAtIndex:0];
            }
            else {
                LocationAtHome *locationAtHome =
                [NSEntityDescription
                 insertNewObjectForEntityForName:@"LocationAtHome"
                 inManagedObjectContext:cdh.context];
                NSError *error = nil;
                if (![cdh.context obtainPermanentIDsForObjects:
                      [NSArray arrayWithObject:locationAtHome] error:&amp;error]) {
                    NSLog(@"Couldn't obtain a permanent ID for object %@",
                          error);
                }
                locationAtHome.storedIn = @"..Unknown Location..";
                item.locationAtHome = locationAtHome;
            }
        }
    }
}
- (void)ensureItemShopLocationIsNotNull {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (self.selectedItemID) {
        CoreDataHelper *cdh =
        [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
        Item *item =
        (Item*)[cdh.context existingObjectWithID:self.selectedItemID
                                           error:nil];
        if (!item.locationAtShop) {
            NSFetchRequest *request =
            [[cdh model]
             fetchRequestTemplateForName:@"UnknownLocationAtShop"];
            NSArray *fetchedObjects =
            [cdh.context executeFetchRequest:request error:nil];

            if ([fetchedObjects count] &gt; 0) {
                item.locationAtShop = [fetchedObjects objectAtIndex:0];
            }
            else {
                LocationAtShop *locationAtShop =
                [NSEntityDescription
                 insertNewObjectForEntityForName:@"LocationAtShop"
                 inManagedObjectContext:cdh.context];
                NSError *error = nil;
                if (![cdh.context obtainPermanentIDsForObjects:
                      [NSArray arrayWithObject:locationAtShop] error:&amp;error]) {
                    NSLog(@"Couldn't obtain a permanent ID for object %@",
                          error);
                }
                locationAtShop.aisle = @"..Unknown Location..";
                item.locationAtShop = locationAtShop;
            }
        }
    }
}

#pragma mark - PICKERS
- (void)selectedObjectID:(NSManagedObjectID *)objectID
      changedForPickerTF:(CoreDataPickerTF *)pickerTF {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (self.selectedItemID) {
        CoreDataHelper *cdh =
        [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];

        Item *item =
        (Item*)[cdh.context existingObjectWithID:self.selectedItemID
                                           error:nil];;
        NSError *error;
        if (pickerTF == self.unitPickerTextField) {
            Unit *unit = (Unit*)[cdh.context existingObjectWithID:objectID
                                                            error:&amp;error];
            item.unit = unit;
            self.unitPickerTextField.text = item.unit.name;
        }
        else if (pickerTF == self.homeLocationPickerTextField) {
            LocationAtHome *locationAtHome =
            (LocationAtHome*)[cdh.context existingObjectWithID:objectID
                                                         error:&amp;error];
            item.locationAtHome = locationAtHome;
            self.homeLocationPickerTextField.text =
            item.locationAtHome.storedIn;
        }
        else if (pickerTF == self.shopLocationPickerTextField) {
            LocationAtShop *locationAtShop =
            (LocationAtShop*)[cdh.context existingObjectWithID:objectID
                                                         error:&amp;error];
            item.locationAtShop = locationAtShop;
            self.shopLocationPickerTextField.text =
            item.locationAtShop.aisle;
        }
        [self refreshInterface];
        if (error) {
            NSLog(@"Error selecting object on picker: %@, %@",
                  error, error.localizedDescription);
        }
    }
}
- (void)selectedObjectClearedForPickerTF:(CoreDataPickerTF *)pickerTF {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (self.selectedItemID) {
        CoreDataHelper *cdh =
        [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
        Item *item =
        (Item*)[cdh.context existingObjectWithID:self.selectedItemID
                                           error:nil];

        if (pickerTF == self.unitPickerTextField) {
            item.unit = nil;
            self.unitPickerTextField.text = @"";
        }
        else if (pickerTF == self.homeLocationPickerTextField) {
            item.LocationAtHome = nil;
            self.homeLocationPickerTextField.text = @"";
        }
        else if (pickerTF == self.shopLocationPickerTextField) {
            item.LocationAtShop = nil;
            self.shopLocationPickerTextField.text = @"";
        }
        [self refreshInterface];
    }
}

#pragma mark - CAMERA
- (void)checkCamera {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    self.cameraButton.enabled =
    [UIImagePickerController
     isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];
}
- (IBAction)showCamera:(id)sender {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if ([UIImagePickerController
         isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
    {
        NSLog(@"Camera is available");
        _camera = [[UIImagePickerController alloc] init];
        _camera.sourceType = UIImagePickerControllerSourceTypeCamera;
        _camera.mediaTypes =
        [UIImagePickerController
         availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];
        _camera.allowsEditing = YES;
        _camera.delegate = self;
        [self.navigationController presentViewController:_camera
                                                animated:YES
                                              completion:nil];
    }
    else
    {
        NSLog(@"Camera not available");
    }
}
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    CoreDataHelper *cdh =
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];

    Item *item =
    (Item*)[cdh.context existingObjectWithID:self.selectedItemID error:nil];

    UIImage *photo =
    (UIImage *)[info objectForKey:UIImagePickerControllerEditedImage];

    NSLog(@"Captured %f x %f photo",photo.size.height, photo.size.width);

    if (!item.photo) { // Create photo object it doesn't exist
        Item_Photo *newPhoto =
        [NSEntityDescription insertNewObjectForEntityForName:@"Item_Photo"
                                      inManagedObjectContext:cdh.context];
        [cdh.context obtainPermanentIDsForObjects:
         [NSArray arrayWithObject:newPhoto] error:nil];
        item.photo = newPhoto;
    }
    item.photo.data = UIImageJPEGRepresentation(photo, 0.5);
    item.thumbnail = nil;

    self.photoImageView.image = photo;

    [picker dismissViewControllerAnimated:YES completion:nil];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [picker dismissViewControllerAnimated:YES completion:nil];
}

@end

vc

 

View – UnitesTVC

 

#import "UnitsTVC.h"
#import "CoreDataHelper.h"
#import "AppDelegate.h"
#import "Unit.h"
#import "UnitVC.h"

@implementation UnitsTVC
#define debug 0

#pragma mark - DATA
- (void)configureFetch {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    CoreDataHelper *cdh =
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
    NSFetchRequest *request =
    [NSFetchRequest fetchRequestWithEntityName:@"Unit"];
    request.sortDescriptors = [NSArray arrayWithObjects:
                               [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES],nil];
    [request setFetchBatchSize:15];
    self.frc =
    [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                        managedObjectContext:cdh.context
                                          sectionNameKeyPath:nil
                                                   cacheName:nil];
    self.frc.delegate = self;
}

#pragma mark - VIEW
- (void)viewDidLoad {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [super viewDidLoad];
    [self configureFetch];
    [self performFetch];
    // Respond to changes in underlying store
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(performFetch)
                                                 name:@"SomethingChanged"
                                               object:nil];
}
- (UITableViewCell*)tableView:(UITableView *)tableView
        cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    static NSString *cellIdentifier = @"Unit Cell";
    UITableViewCell *cell =
    [tableView dequeueReusableCellWithIdentifier:cellIdentifier
                                    forIndexPath:indexPath];
    Unit *unit = [self.frc objectAtIndexPath:indexPath];
    cell.textLabel.text = unit.name;
    return cell;
}
- (void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        Unit *deleteTarget = [self.frc objectAtIndexPath:indexPath];
        [self.frc.managedObjectContext deleteObject:deleteTarget];
        [self.tableView reloadRowsAtIndexPaths:
         [NSArray arrayWithObject:indexPath]
                              withRowAnimation:UITableViewRowAnimationFade];
    }

    CoreDataHelper *cdh = [(AppDelegate *)[[UIApplication
                                            sharedApplication] delegate] cdh];
    [cdh backgroundSaveContext];
}

#pragma mark - INTERACTION
- (IBAction)done:(id)sender {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [self.parentViewController
     dismissViewControllerAnimated:YES completion:nil];
}

#pragma mark - SEGUE
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    UnitVC *unitVC = segue.destinationViewController;
    if ([segue.identifier isEqualToString:@"Add Object Segue"])
    {
        CoreDataHelper *cdh =
        [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
        Unit *newUnit =
        [NSEntityDescription insertNewObjectForEntityForName:@"Unit"
                                      inManagedObjectContext:cdh.context];
        NSError *error = nil;
        if (![cdh.context obtainPermanentIDsForObjects:
              [NSArray arrayWithObject:newUnit] error:&amp;error]) {
            NSLog(@"Couldn't obtain a permanent ID for object %@", error);
        }
        unitVC.selectedObjectID = newUnit.objectID;
    }
    else if ([segue.identifier isEqualToString:@"Edit Object Segue"])
    {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        unitVC.selectedObjectID =
        [[self.frc objectAtIndexPath:indexPath] objectID];
    }
    else {
        NSLog(@"Unidentified Segue Attempted!");
    }
}

@end
#import &lt;UIKit/UIKit.h&gt;
#import "CoreDataHelper.h"
@interface UnitVC : UIViewController 
@property (strong, nonatomic) NSManagedObjectID *selectedObjectID;
@property (strong, nonatomic) IBOutlet UITextField *nameTextField;
@end

#import "UnitVC.h"
#import "Unit.h"
#import "AppDelegate.h"

@implementation UnitVC
#define debug 0

#pragma mark - VIEW
- (void)refreshInterface {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (self.selectedObjectID) {
        CoreDataHelper *cdh =
        [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
        Unit *unit =
        (Unit*)[cdh.context existingObjectWithID:self.selectedObjectID
                                           error:nil];
        self.nameTextField.text = unit.name;
    }
}
- (void)viewDidLoad {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [super viewDidLoad];
    [self hideKeyboardWhenBackgroundIsTapped];
    self.nameTextField.delegate = self;
}
- (void)viewWillAppear:(BOOL)animated {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [self refreshInterface];
    [self.nameTextField becomeFirstResponder];
}
- (void)viewDidDisappear:(BOOL)animated {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    CoreDataHelper *cdh =
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
    [cdh backgroundSaveContext];
    [[NSNotificationCenter defaultCenter] postNotificationName:@"SomethingChanged"
                                                        object:nil
                                                      userInfo:nil];
}

#pragma mark - TEXTFIELD
- (void)textFieldDidEndEditing:(UITextField *)textField {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    CoreDataHelper *cdh =
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
    Unit *unit =
    (Unit*)[cdh.context existingObjectWithID:self.selectedObjectID
                                       error:nil];
    if (textField == self.nameTextField) {
        unit.name = self.nameTextField.text;
        [[NSNotificationCenter defaultCenter]
         postNotificationName:@"SomethingChanged"
         object:nil];
    }
}

#pragma mark - INTERACTION
- (IBAction)done:(id)sender {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [self hideKeyboard];
    [self.navigationController popViewControllerAnimated:YES];
}
- (void)hideKeyboardWhenBackgroundIsTapped {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    UITapGestureRecognizer *tgr =
    [[UITapGestureRecognizer alloc] initWithTarget:self
                                            action:@selector(hideKeyboard)];
    [tgr setCancelsTouchesInView:NO];
    [self.view addGestureRecognizer:tgr];
}
- (void)hideKeyboard {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [self.view endEditing:YES];
}
@end

CoreDataPickerTF 此VC是textField的subclass, 并且定义两个dalegate, 供itemvc调用数据时用;

CoreDataPickerTF

#import &lt;UIKit/UIKit.h&gt;
#import "CoreDataHelper.h"
@class CoreDataPickerTF;
@protocol CoreDataPickerTFDelegate 
- (void)selectedObjectID:(NSManagedObjectID*)objectID
      changedForPickerTF:(CoreDataPickerTF*)pickerTF;
@optional
- (void)selectedObjectClearedForPickerTF:(CoreDataPickerTF*)pickerTF;
@end

@interface CoreDataPickerTF : UITextField
&lt;UIKeyInput, UIPickerViewDelegate, UIPickerViewDataSource&gt;
@property (nonatomic, weak) id  pickerDelegate;
@property (nonatomic, strong) UIPickerView *picker;
@property (nonatomic, strong) NSArray *pickerData;
@property (nonatomic, strong) UIToolbar *toolbar;
@property (nonatomic) BOOL showToolbar;
@property (nonatomic, strong) NSManagedObjectID *selectedObjectID;
@end

#import "CoreDataPickerTF.h"
@implementation CoreDataPickerTF
#define debug 0

#pragma mark - DELEGATE &amp; DATASOURCE: UIPickerView
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    return [self.pickerData count];
}
- (CGFloat)pickerView:(UIPickerView *)pickerView
rowHeightForComponent:(NSInteger)component {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    return 44.0f;
}
- (CGFloat)pickerView:(UIPickerView *)pickerView
    widthForComponent:(NSInteger)component {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    return 280.0f;
}
- (NSString *)pickerView:(UIPickerView *)pickerView
             titleForRow:(NSInteger)row
            forComponent:(NSInteger)component {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    return [self.pickerData objectAtIndex:row];
}
- (void)pickerView:(UIPickerView *)pickerView
      didSelectRow:(NSInteger)row
       inComponent:(NSInteger)component {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    NSManagedObject *object = [self.pickerData objectAtIndex:row];
    [self.pickerDelegate selectedObjectID:object.objectID
                       changedForPickerTF:self];
}

#pragma mark - INTERACTION
- (void)done {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [self resignFirstResponder];
}
- (void)clear {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [self.pickerDelegate selectedObjectClearedForPickerTF:self];
    [self resignFirstResponder];
}

#pragma mark - DATA
- (void)fetch {
    [NSException raise:NSInternalInconsistencyException format:
     @"You must override the '%@' method to provide data to the picker",
     NSStringFromSelector(_cmd)];
}
- (void)selectDefaultRow {
    [NSException raise:NSInternalInconsistencyException format:
     @"You must override the '%@' method to set the default picker row",
     NSStringFromSelector(_cmd)];
}

#pragma mark - VIEW
- (UIView *)createInputView {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    self.picker = [[UIPickerView alloc] initWithFrame:CGRectZero];
    self.picker.showsSelectionIndicator = YES;
    self.picker.autoresizingMask = UIViewAutoresizingFlexibleHeight;
    self.picker.dataSource = self;
    self.picker.delegate = self;
    [self fetch];
    return self.picker;
}
- (UIView *)createInputAccessoryView {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    self.showToolbar = YES;
    if (!self.toolbar &amp;&amp; self.showToolbar) {
        self.toolbar = [[UIToolbar alloc] init];
        self.toolbar.barStyle = UIBarStyleBlackTranslucent;
        self.toolbar.autoresizingMask = UIViewAutoresizingFlexibleHeight;
        [self.toolbar sizeToFit];
        CGRect frame = self.toolbar.frame;
        frame.size.height = 44.0f;
        self.toolbar.frame = frame;
        UIBarButtonItem *clearBtn = [[UIBarButtonItem alloc]
                                     initWithTitle:@"Clear"
                                     style:UIBarButtonItemStyleBordered
                                     target:self
                                     action:@selector(clear)];
        UIBarButtonItem *spacer = [[UIBarButtonItem alloc]
                                   initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
                                   target:nil
                                   action:nil];
        UIBarButtonItem *doneBtn =[[UIBarButtonItem alloc]
                                   initWithBarButtonSystemItem:UIBarButtonSystemItemDone
                                   target:self
                                   action:@selector(done)];
        NSArray *array =
        [NSArray arrayWithObjects:clearBtn, spacer, doneBtn, nil];
        [self.toolbar setItems:array];
    }
    return self.toolbar;
}
-  (id)initWithFrame:(CGRect)aRect {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (self = [super initWithFrame:aRect]) {

        self.inputView = [self createInputView];
        self.inputAccessoryView = [self createInputAccessoryView];
    }
    return self;
}
- (id)initWithCoder:(NSCoder*)aDecoder {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (self = [super initWithCoder:aDecoder]) {
        self.inputView = [self createInputView];
        self.inputAccessoryView = [self createInputAccessoryView];
    }
    return self;
}
- (void)deviceDidRotate:(NSNotification*)notification {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    [self.picker setNeedsLayout];
}

@end

UnitPickerTF subclass of CoreDataPickerTF

难点: enumerateObjectsUsingBlock

#import "CoreDataPickerTF.h"

@interface UnitPickerTF : CoreDataPickerTF

- (void)fetch;

@end

#import "UnitPickerTF.h"
#import "CoreDataHelper.h"
#import "AppDelegate.h"
#import "Unit.h"
@implementation UnitPickerTF
#define debug 0
- (void)fetch {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    CoreDataHelper *cdh =
    [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
    NSFetchRequest *request =
    [NSFetchRequest fetchRequestWithEntityName:@"Unit"];
    NSSortDescriptor *sort =
    [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
    [request setSortDescriptors:[NSArray arrayWithObject:sort]];
    [request setFetchBatchSize:15];
    NSError *error;
    self.pickerData = [cdh.context executeFetchRequest:request
                                                 error:&amp;error];
    if (error) {
        NSLog(@"Error populating picker: %@, %@"
              , error, error.localizedDescription);}
    [self selectDefaultRow];
}
- (void)selectDefaultRow {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    if (self.selectedObjectID &amp;&amp; [self.pickerData count] &gt; 0) {
        CoreDataHelper *cdh =
        [(AppDelegate *)[[UIApplication sharedApplication] delegate] cdh];
        Unit *selectedObject =
        (Unit*)[cdh.context existingObjectWithID:self.selectedObjectID
                                           error:nil];
        [self.pickerData enumerateObjectsUsingBlock:^(
                                                      Unit *unit, NSUInteger idx, BOOL *stop) {
            if ([unit.name compare:selectedObject.name] == NSOrderedSame) {
                [self.picker selectRow:idx inComponent:0 animated:NO];
                [self.pickerDelegate selectedObjectID:self.selectedObjectID
                                   changedForPickerTF:self];
                *stop = YES;
            }
        }];
    }
}
- (NSString *)pickerView:(UIPickerView *)pickerView
             titleForRow:(NSInteger)row
            forComponent:(NSInteger)component {
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    Unit *unit = [self.pickerData objectAtIndex:row];
    return unit.name;
}
@end

If the user modifies items during the import process, there is the potential that the same object could be modified in two contexts at the same time. When one of those contexts is then saved, a merge conflict could result. To handle merge conflicts, a merge policy will be configured in advance. The merge policy decides who wins when these conflicts arise. There are five options:

NSErrorMergePolicy is the default policy. Merge conflicts prevent the context from being saved.

NSMergeByPropertyObjectTrumpMergePolicy resolves merge conflicts using object
property values from the context to overwrite those in the persistent store.
NSMergeByPropertyStoreTrumpMergePolicy resolves merge conflicts using object property values from the persistent store to overwrite those in the context.
NSOverwriteMergePolicy resolves merge conflicts using entire objects from the context to overwrite those in the persistent store.
NSRollbackMergePolicy resolves merge conflicts using entire objects from the persistent store to overwrite those in the context.