Amarronの日記

iOSやMac、Web系の記事を書きます。

iOS HTTP メモ

  • iOSのHTTP関係のプログラムやメモです
  • 随時更新していく予定です

Flow


HTTP リクエストを発行しレスポンスを受信するまでのプログラムの流れはだいたい次の通り。

NSURLConnectionの場合

  1. リクエストヘッダ(NSURLRequest)を作る
  2. NSURLConnectionのクラスメソッドを用いリクエストを発行する
  3. レスポンスヘッダ(NSURLResponse)とレスポンスボディを取得する

NSURLSessionの場合

  1. セッションクラス(NSURLSession)を作る
  2. タスクを生成する
  3. タスクの実行する
// playgroundの場合↓のコメントアウトを消す
// import XCPlayground

/*
* NSURLConnection(非同期)
*/
func myNSURLConnectionAsync() {
    // 通信先のURLを生成.
    let url:NSURL = NSURL(string:"http://httpbin.org/get")!
    // リクエストを生成.
    let request:NSURLRequest = NSURLRequest(URL:url)
    let queue:NSOperationQueue = NSOperationQueue()
    // NSURLConnectionを使ってアクセス
    NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
        // 帰ってきたデータを文字列に変換.
        var result = NSString(data: data, encoding: NSUTF8StringEncoding)!
        println("myNSURLConnectionAsync->\(result)")
    })

    // playgroundの場合↓のコメントアウトを消す
    // XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)
}

/*
* NSURLConnection(同期)
*/
func myNSURLConnectionSync() {
    // 通信先のURLを生成.
    let url:NSURL = NSURL(string:"http://httpbin.org/get")!
    // リクエストを生成.
    let request:NSURLRequest = NSURLRequest(URL:url)
    // NSURLConnectionを使ってアクセス
    var response: NSURLResponse?
    var error: NSError?
    let data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error)
    var result = NSString(data: data!, encoding: NSUTF8StringEncoding)!
    println("myNSURLConnectionSync->\(result)")
    
    // playgroundの場合↓のコメントアウトを消す
    // XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)
}

/*
* NSURLSession(非同期)
*/
func myNSURLSession() {
    // 通信先のURLを生成.
    let url:NSURL = NSURL(string: "http://httpbin.org/get")!
    // セッションの生成.
    let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
    // 通信のタスクを生成.
    let task = session.dataTaskWithURL(url, completionHandler: {
        (data, response, err) in
        
        // 帰ってきたデータを文字列に変換.
        var result = NSString(data: data, encoding: NSUTF8StringEncoding)!
        println("myNSURLSession->\(result)")
        
    })
    // タスクの実行.
    task.resume()

    // playgroundの場合↓のコメントアウトを消す
    // XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)
}

参考UTL:NSURLSession のまとめ

Json


jsonを取得しパース

func myNSURLConnectionSync() {
    // 通信先のURLを生成.
    let url:NSURL = NSURL(string:"http://httpbin.org/get")!
    // リクエストを生成.
    let request:NSURLRequest = NSURLRequest(URL:url)
    // NSURLConnectionを使ってアクセス
    var response: NSURLResponse?
    var error: NSError?
    let data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error)
//    var result = NSString(data: data!, encoding: NSUTF8StringEncoding)!
//    println("myNSURLConnectionSync->\(result)")
    
    // Jsonでパース
    let json:NSDictionary = NSJSONSerialization.JSONObjectWithData(data!,
        options: NSJSONReadingOptions.AllowFragments, error: nil) as! NSDictionary
    for (name, value) in json {
        println("key:\(name) value:\(value)")
    }
}

GCD


GCDを使った非同期完了後の処理

func myNSURLConnectionAsync() {
    // 通信先のURLを生成.
    let url:NSURL = NSURL(string:"http://httpbin.org/get")!
    // リクエストを生成.
    let request:NSURLRequest = NSURLRequest(URL:url)
    let queue:NSOperationQueue = NSOperationQueue()
    // NSURLConnectionを使ってアクセス
    NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
        // 帰ってきたデータを文字列に変換.
        var result = NSString(data: data, encoding: NSUTF8StringEncoding)!
        println("myNSURLConnectionAsync->\(result)")
        
        // GCD(Grand Central Dispatch)
         dispatch_async(dispatch_get_main_queue(), {
              // 完了後に実行する処理(self.tableView.reloadData()等)
          })
    })

}

参考URL:[Swift 1.1] swiftで api を叩いて、JSONをパースして、表示させる方法 (xcodeは6.1, iOSは8.1)

Auth


cookie


Cookieの永続化

// Cookieの永続化
import UIKit

class AppDelegate: UIResponder, UIApplicationDelegate {
    let SavedHTTPCookiesKey = "SavedHTTPCookies"

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
            self.window = UIWindow(frame: UIScreen.mainScreen().bounds)

        self.loadCookie()
        
        return true
    }
    func applicationDidEnterBackground(application: UIApplication) {
        
        self.saveCookie()
    }

    func saveCookie() {
        let cookiesData:NSData = NSKeyedArchiver.archivedDataWithRootObject(NSHTTPCookieStorage.sharedHTTPCookieStorage().cookies!)
        NSUserDefaults.standardUserDefaults().setObject(cookiesData, forKey: SavedHTTPCookiesKey)
    }
    
    func loadCookie() {
        if let cookiesData:NSData = NSUserDefaults.standardUserDefaults().objectForKey(SavedHTTPCookiesKey) as? NSData {
            for cookie:NSHTTPCookie in NSKeyedUnarchiver.unarchiveObjectWithData(cookiesData) as [NSHTTPCookie] {
                NSHTTPCookieStorage.sharedHTTPCookieStorage().setCookie(cookie)
            }
        }
    }
}

Custom URL Scheme


  • Custom URL Schemeの処理をシンプルに書く
    • URLの設計:scheme://controller/action?query
    • アプリ側は受け取ったcontrollerを元に、使用するcontrollerクラスを選び、そのcontrollerクラスにactionとqueryを渡す。
    • 各actionの挙動については各々のcontrollerに任せる
import UIKit

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?) -> Bool {
        var result:Bool = true

        let schema:String = url.scheme!
        let host:String   = url.host!
        let action:String = url.lastPathComponent!
        let query:String  = url.query!
        return result
    }
}

外部ライブラリ


note

  • 特にこだわりがないようであれば、Alamofireを使ったほうがよさそう(画像のキャッシュとか自分でコードを書く量が最終的に少なくてすみそう) f:id:Amarron:20150401221639p:plain

HTTPの確認に便利


参考URL


プッシュ通知 証明書 更新 手順

更新手順


No. 内容 Development Product 備考
0 KeyChain(開発環境)->証明局に証明書(CertificateSigningRequest.certSigningRequest)を要求 Development・Product共通、複数のアプリで共通で使う
1 Deveropper Center(Safari)->Certificates の作成 アプリごと、No.0で要求した「CertificateSigningRequest.certSigningRequest」ファイルを使う
2 Deveropper Center(Safari)->Provisioning Profiles の更新 アプリごとに対応必要。アプリのバージョンアップ時に必要
2 Xcode(開発環境)->Buid Setting->Provisioning Profile のダウンロード アプリごとに対応必要。アプリのバージョンアップ時に必要。新しくProvisioning Profileは作成されるが、特に更新しなくてもプッシュ通知は受信できる
3 KeyChain(開発環境)->p12ファイルを書き出す アプリごとに対応必要。鍵ではなく証明書で書きだす
  • No.0
    • f:id:Amarron:20150401221129p:plain
  • No.3
    • f:id:Amarron:20150401221114p:plain

手順

  1. Certificates の削除(更新前のCertificatesの有効期限が切れていない場合)・作成(Apple Push Notification service SSL)→作成後ダウンロード
  2. Provisioning Profiles の更新
  3. p12ファイルを書き出す(キーチェーンより「1.Certificates」で作成した証明書を選択し書き出し)
  4. p12ファイルの鍵を書き出す(キーチェーンより「1.Certificates」で作成した鍵を選択し書き出し)(サーバー側で必要であれば)
  5. p12をpemファイルへ変換する(サーバー側で必要であれば)
  6. サーバへp12またはpemファイルを配布

p12からpemへの変換コマンド

openssl pkcs12 -clcerts -nokeys -out apns-dev-cert.pem -in apns-dev-cert.p12  
openssl pkcs12 -nocerts -out apns-dev-key.pem -in apns-dev-key.p12  
openssl rsa -in apns-dev-key.pem -out apns-dev-key-noenc.pem  
cat apns-dev-cert.pem apns-dev-key-noenc.pem > apns-dev.pem

参考URL

プッシュ通知文字数(おまけ)


表示箇所 iOS6 iOS7
ステータスバー(画面上部) 全角22文字、半角40文字 全角35文字、半角64文字
ダイアログ(ロック画面に表示) 全角57文字、半角108文字 全角58文字、半角114文字
通知センター 全角43文字、半角154文字 全角58文字、半角114文字

参考URL:http://www.hangout.co.jp/blog/archives/295

iOS 開発 カメラ

  • iOS(iPhone,iPad)のカメラ、写真の開発時のメモです
  • カメラを起動したり、フォトアルバムから写真を選択してアプリに渡したりできます
  • アプリで高解像度(1MB以上)の写真や画像を大量に表示するとメモリ不足でクラッシュします(100KB位まで解像度を下げるのがオススメ)

f:id:Amarron:20150320001518p:plain

写真やムービーの撮影


  • 2つのテクノロジー
    1. UIImagePickerController:カスタマイズ可能な基本的なユーザイン ターフェイス
    2. AVFoundation FW:UIKitと一緒に使用し完全にカスタマイズした静止画像やムービーのキャプチャ機能をアプリケーション向けに作成することができる
  • どちらを採用する場合も、Assets Library FWを使用して、メディアのメタデータGPS位置情報など)を管理できる

保存済みの写真やムービーをユーザのフォトアルバムから選択


  • 2つのテクノロジー
    1. UIImagePickerController:基本的なユーザインターフェイスを使用してユーザがフォトライブラリからメディアを選択できる
    2. Assets Library FW:UIKitと一緒に使用し完全にカスタマイズした写真やムービーのブラウザを作成できる

Image Picker Controllerを利用した写真やムービーの撮影


  1. カメラインターフェイス(UIImagePickerControllerクラスのインスタンス)をインスタンス化してモーダルモードで表示
  2. システムは、このカメラインターフェイスとユーザとのやり取りを管理(ユーザが写真やムービーを撮影、またはキャンセル)
  3. システムはImagePickerControllerのデリゲートオブジェクトのメソッドを呼び出し今度は、このメソッドがユーザの操作(たとえば、新規の写真を「カメラロール(Camera Roll)」アルバムに保存する)の結果を処理。(カメラインターフェイスを消去するのもデリゲート)

参考URL


iOS 保存領域 比較 〜NSUserDefaults, CoreData,Keychain,等〜

アプリ容量の制限について


アプリのストレージの最大容量は、おそらく制限なし(20M以上だとDL時にwifiが必要となる)

f:id:Amarron:20150314205528j:plain

保存領域について


種類 説明
アプリ領域 アプリが自由に使え、他のアプリから参照できない領域
OS領域 OSが使用するデータが保存されており、基本的にアプリから参照できない領域
共有領域 メディアライブラリ(写真、音楽等)やイベント(カレンダー等)、連絡先は全てのアプリから参照することができる領域(アプリからできる内容は、書き込みと閲覧のみ)

永続データの復元(比較)について


  • 復元時にデータも復元するには、外部サーバーにデータを保存するかiCloudを利用しないと殆ど初期化される
  • 保存領域が共有領域であれば、アプリ自体にiCloudの処理をいれなくても、共有領域のデータは復元できそう
種類 復元可否 備考
アーカイブ オブジェクトをバイナリ形式に変換してからファイルに永続化(一番基礎的な技術)
プロパティリスト - ユーザーが変更しないもの(定数)、plist
NSUserDefaults ユーザーが変更するもの
CoreData データ量多い
Keychain パスワードや個人情報(暗号化されていない場合復元されない)

アプリ内にDBとして保存したい場合realmがオススメです。(日本語のドキュメントもしっかりしていて、組み込みも簡単で、ブラウザも用意されています)

参考URL


Xcode デバッグ 値変更

概要

  • Xcodeでデバック中に、変数の値や関数の実行する方法の説明です
  • デバックエリアでLLDBコマンドを実行して確認します
  • 値の変更はデバックエリアで「po 変数名 = 値」で変更できます

LLDBとは、Mac OS X上のXcodeでデフォルトのデバッガで、デスクトップとiOSデバイスとシミュレータ上のC、のObjective-CC++Swiftデバッグをサポートしています。

f:id:Amarron:20150314202752p:plain

実行方法

  1. デバックエリアを表示(メニューバー->View->Debug Area->Show Debug Area)
  2. 止めたいところにブレークポイント設定
  3. プログラムの実行
  4. デバックエリアでLLDBコマンドの実行

実行例

  • 変数の値や関数の実行する場合は、「(lldb) po 変数名 または 関数名」を実行します

f:id:Amarron:20150314202812p:plain 「po self.dynamicType」でプロジェクト名とクラス名を表示している例

LLDBコマンド一覧(一部抜粋)

省略形 内容 正式名
po 式の評価(poはオブジェクト、pは基本型も可) expression -o --
h ヘルプの表示 help
s ステップイン thread step-in
c 続きを実行(次のbreakPointまで) process continue
br l breakPointを一覧表示 breakpoint list
bt 現スレッドのバックトレース情報を表示 thread backtrace

iOS AdMob 実装 方法

AdMob SDKの導入方法や手順が書いてあります。(iPhoneiPadが対象)

やりたいこと

iOSアプリにAdMobのバナー広告を表示させたい。
(AdMobとは、Googleが運営するアプリ専門のアドネットワーク。日本国内の収益性は微妙だが、海外の広告案件が豊富。)

f:id:Amarron:20150215023503p:plain

流れ

  1. AdMobに登録
  2. アプリにSDK組込
  3. 広告ユニットIDの作成

細かい部分はAdMobのスターターズガイドがしっかりしているので、その通り進めば多分大丈夫だと思います。

1. AdMobに登録

AdMobのサイトでユーザー登録をします。
「Sign Up」ボタン押下後適当に個人情報を入力して進みます。
(全文英語ですが、一般的なユーザー登録なので英語読めなくても何とかなるはず。。。)

f:id:Amarron:20150215024507p:plain

2. アプリにSDK組込

今回は、CocoaPodsを利用してSDKを組込みます。
CocoaPodsの利用方法がわからない方はこちら

f:id:Amarron:20150215023529p:plain

2-1. Podfileの作成・SDKインストール

ターミナルを起動しPodfileを作成しSDKをインストールします。

$ vi Podfile   # Podfileの作成
platform :ios, '8.0'
pod 'Google-Mobile-Ads-SDK', '~> 7.0'
$ pod install  # SDKインストール
Analyzing dependencies

CocoaPods 0.36.0.beta.2 is available.
To update use: `gem install cocoapods --pre`
[!] This is a test version we'd love you to try.

For more information see http://blog.cocoapods.org
and the CHANGELOG for this version http://git.io/BaH8pQ.

Downloading dependencies
Installing Google-Mobile-Ads-SDK (7.0.0)
Generating Pods project
Integrating client project

[!] From now on use `BannerExample.xcworkspace`.
$  # 「プロジェクト名.xcworkspace」が作成されていればインストール完了!

2-2. AdMobを実装

とりあえずSDKが読み込めているか試してみましょう

# swift
// Bridging-Header.h
@import GoogleMobileAds

// BannerExampleViewController.swift
class BannerExampleViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        println("Google Mobile Ads SDK version:\(GADRequest.sdkVersion())")
    }
 }
# Objective-C
// BannerExampleViewController.m

@import GoogleMobileAds;
#import "ViewController.h"

@implementation BannerExampleViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  NSLog(@"Google Mobile Ads SDK version: %@", [GADRequest sdkVersion]);
}

@end

次に、バナーを作成し画面表示されたらOKです。
広告ユニットIDは、「3. 広告ユニットIDの作成」で作成し自分のIDに変更しましょう

# swift
// BannerExampleViewController.swift

// GADBannerViewDelegateを追加
class BannerExampleViewController, GADBannerViewDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        println("Google Mobile Ads SDK version:\(GADRequest.sdkVersion())")
        
        var bannerView: GADBannerView = GADBannerView()
        bannerView = GADBannerView(adSize:kGADAdSizeBanner)
        // 広告ユニットIDを指定する(3. 広告ユニットIDの作成参照)
        bannerView.adUnitID = "ca-app-pub-3940256099942544/2934735716" 
        bannerView.delegate = self
        bannerView.rootViewController = self
        self.view.addSubview(bannerView)
        bannerView.loadRequest(GADRequest())
    }
}
# Objective-C
// BannerExampleViewController.h

// SDK から GADBannerView の定義をインポートする
#import "GADBannerView.h"

@interface BannerExampleViewController : UIViewController {
  // インスタンス変数として 1 つ宣言する
  GADBannerView *bannerView_;
}

@end

// BannerExampleViewController.m

#import "BannerExampleViewController.h"

@implementation BannerExampleViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  // 画面上部に標準サイズのビューを作成する
  // 利用可能な広告サイズの定数値は GADAdSize.h で説明されている
  bannerView_ = [[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner];

        // 広告ユニットIDを指定する(3. 広告ユニットIDの作成参照)  bannerView_.adUnitID = MY_BANNER_UNIT_ID;

  // ユーザーに広告を表示した場所に後で復元する UIViewController をランタイムに知らせて
  // ビュー階層に追加する
  bannerView_.rootViewController = self;
  [self.view addSubview:bannerView_];

  // 一般的なリクエストを行って広告を読み込む
  [bannerView_ loadRequest:[GADRequest request]];
}

- (void)dealloc {

  // プロジェクトで ARC を使用している場合は bannerView_ を解放しない
  [bannerView_ release];
  [super dealloc];
}

@end

広告のサイズやターゲットの設定はこちら

3. 広告ユニットIDの作成

  1. AdMob管理画面に「1. AdMobに登録」で作成したアカウントでログイン
  2. 広告ユニットIDの作成
    1. 「収益化->新しいアプリの収益化」ページまで移動
    2. アプリを追加
    3. 広告フォーマットの選択と広告ユニット名の設定
    4. 表示の設定方法
    5. 完了ボタン押下
  3. 広告ユニットIDをアプリに設定
    1. 「収益化->すべてのアプリ」ページまで移動
    2. 自分が追加したアプリの「広告ID」が発行されています

      f:id:Amarron:20150215023554p:plain

    3. 「2-2. AdMobを実装」で設定していた「広告ID」を自分の「広告ID」に変更しましょう

  4. 表示と計測の確認
    1. アプリを起動し広告が表示されているか確認しましょう(広告IDを変更した場合、よく見かける一般的な広告に差し替わっていると思います。)
    2. 広告を押下し外部サービスが起動することを確認しましょう
    3. 管理画面上で計測が正しくとれていることを確認しましょう(リアルタイムに反映されないので時間を置いて確認しましょう(私の場合1時間位で反映されていました))

以上で全て終了です。お疲れ様でした!

CoreData の 関連図 と 手順

概要

  • CoreDataの知識が曖昧だったのでクラスの関連図や手順についてのメモです(細かい実装方法や使い方は他の参考サイトを参考にしてください)
  • DB自体初めての人には登場人物が多くて難易度高めな気がします
  • 参考資料:iOS Core Data チュートリアル

関連図

f:id:Amarron:20150121224913p:plain

Core Data RDB
NSManagedObjectModel DB
Entity Table
NSManagedObject Record
Attribute Column
  • NSManagedObjectModel:管理オブジェクトモデル(データベース)

f:id:Amarron:20150121224955p:plain

  • NSManagedObject:管理オブジェクト(レコード)
  • NSManagedObjectContext:管理オブジェクトコンテキスト(オブジェクト空間、管理オブジェクトのコレクションを管理する)

f:id:Amarron:20150121225004p:plain

  • NSPersistentStoreCoordinator:永続ストアコーディネータ(ストアを管理して、管理オブジェクトコンテキストに、1つ の統一されたストアのファサードを提供する)

f:id:Amarron:20150121225014p:plain

作成手順

  1. プロジェクトの準備
    • Xcodeで、「iOS」セクションの「Window-basedApplication」テンプレーを使用してプロジェクトを作成します。オプション(Options)(Options)セクションで、ストレージにCore Dataを使用するスイッチ(「Use Core Data for storage」)を選択
      • AppDelegateクラスにCoreData用のプログラムが追加され、【プロジェクト名】.xcdatamodeldが作成される
  2. テーブルの作成
    • Xcodeのデータモデリングツール(プロジェクト名】.xcdatamodeld)を使用して、新規エンティティを作成
    • f:id:Amarron:20150121225041p:plain

    • そのエンティティを表すカスタムクラス(NSManagedObject)を作成(xcdatamodeldを選択し、「Create NSManagedObject」で作成可能)

  3. テーブルにデータ追加
    • NSManagedObjectContextでDML操作(レコードの追加・検索・更新・削除など)
    • NSEntityDescriptionでテーブルの指定
    • NSManagedObjectで値の受け渡し
  4. テーブルからデータ取得
    • NSManagedObjectContextでDML操作(レコードの追加・検索・更新・削除など)
    • NSFetchRequestでテーブルの指定
import CoreData

class MyClass : UIViewController {
// 3. テーブルにデータ追加
@IBAction func insert(sender: AnyObject) { 
        let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
        let managedContext: NSManagedObjectContext = appDelegate.managedObjectContext!
        
        /* Create new ManagedObject */
        let entity = NSEntityDescription.entityForName("テーブル名", inManagedObjectContext: managedContext)
        let personObject = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: managedContext)
        // let myPersonObject = NSManagedObjectを継承したカスタムクラス(entity: entity!, insertIntoManagedObjectContext: managedContext) // 自分で作成したカスタムを使う場合
        
        /* Set the name attribute using key-value coding */
        personObject.setValue("値", forKey: "カラム名")
        // myPersonObject.カラム名 = "値" // 自分で作成したカスタムを使う場合
        
        /* Error handling */
        var error: NSError?
        if !managedContext.save(&error) {
            println("Could not save \(error), \(error?.userInfo)")
        }
        println("object saved")
}

// 4. テーブルからデータ取得
@IBAction func selectAll(sender: AnyObject) { 
        /* Get ManagedObjectContext from AppDelegate */
        let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
        let manageContext:NSManagedObjectContext = appDelegate.managedObjectContext!

        /* Set search conditions */
        let fetchRequest = NSFetchRequest(entityName: "テーブル名")
        var error: NSError?
        
        /* Get result array from ManagedObjectContext */
        let fetchResults = manageContext.executeFetchRequest(fetchRequest, error: &error)
        if let results: Array = fetchResults {
            for obj:AnyObject in results {
                let name:String? = obj.valueForKey("カラム名") as? String
                println(name)
            }
            println(results.count)
        } else {
            println("Could not fetch \(error) , \(error!.userInfo)")
        }
}

まとめ

  • xcdatamodeldでテーブル情報(テーブル名、カラム名、カラム属性、リレーション等)を設定する
  • NSManagedObjectを継承したクラスをテーブルのカラム名を書いて、テーブルとの受け渡し用の入れ物に使う
  • NSManagedObjectContextでDML操作(レコードの追加・検索・更新・削除など)
  • NSEntityDescriptionでテーブルの指定
  • データの保存場所を確認したい場合、applicationDocumentsDirectoryを見る
  • 個人的には、FMDBのライブラリを使って直接SQLでデータをやりとりした方が自由で楽なきがします。。。

参考サイト