Swiftで作るToDoアプリ開発チュートリアル

Swiftで作るToDoアプリ開発チュートリアル

Swift と Xcode を使っての iOS 開発で、ToDo アプリを作ってみる開発のチュートリアルです。ちょっと長いですが、スクリーンショット付きで Xcode の操作方法を解説して、必要となる Swift のソースコードも全て掲載しています。以下画像のような、オーソドックスな ToDo アプリを作っていきます。

swift-todo-69

Todo アプリを操作するデモ動画を YouTube に上げました。以下から確認できます。
Swift/iOS Todo App demo | YouTube

私は Swift と Xcode に取り組み始めて1ヶ月程度の iOS 開発の入門者です。iOS 開発を始めて感じたのは、Swift の文法よりも Xcode の操作が難しいことでした。特に Storyboard で UI を組み立てる作業でつまづきが多かったですので、このチュートリアルでは Xcode / Storyboard のスクリーンショットを豊富に掲載して、GUI 画面での操作が分かりやすくなるように心がけました。間違った記載などがありましたら、ご指摘頂けると助かります!

スポンサーリンク

これから Swift / iOS 開発に取り組み始められる方に参考になれば幸いです。基本的な操作・作業を忘れないように、自分用の備忘録でもあります。Swift の文法や Xcode の基本的な操作法、Storyboard, Auto Layout の基本的な使い方などについては、詳しくは触れていません。初心者の方は、前もってドットインストールなどで学習されておくと分かりやすいかと思います。

iPhoneアプリ開発入門 (全13回) – プログラミングならドットインストール

— このチュートリアルの対象読者 —
Swift / iOS 開発の入門者〜中級者

— 詳しく説明しないこと —
Swift の文法
Xcode の基本的な操作方法
Storyboard の基本的な使い方

— 動作検証の環境 —
Mac OS X Yosemite 10.10.3
Swift 1.2
Xcode 6.3.1 および 6.3.2
Xcode iOS Simulator 8.3
MagicalRecord 2.2

UI は Storyboard を使って組み立てていきます。また、CoreData(iOS 用 SQLite データベースを使うフレームワーク)のラッパーライブラリである MagicalRecord を使用します。

— 目次 —
Xcode 新規プロジェクトの作成
MagicalRecord のインストール
Swift から MagicalRecord を使うための設定
Todo リスト一覧の画面を作成する
Table View の delegate と dataSource の設定
Navigation Controller の追加と Navigation Item の設定
Todo タスク追加の画面を作成する
Cancel, Save ボタンの Action と Text Field の Outlet を作成
Todo タスク用のモデルを作成
UITableViewDelegate, UITableViewDataSource のメソッドを実装
動作確認のためにビルドしてみる
Todo タスクを追加できるようにメソッドを実装
スワイプで Todo タスクを削除できるようにする
Todo List 一覧 → Todo Item の詳細&編集への画面遷移
Todo Item の Text Field に選択されたタスクを表示
Todo タスクを編集できるようにする
遭遇したエラー達

それでは、チュートリアル開始です!

Xcode 新規プロジェクトの作成

まず最初に Xcode 用新規プロジェクトの作成です。
swift-todo-1

Xcode を起動して Create a new Xcode project をクリックします。

あるいは、File → New → Project から新規プロジェクトを作成します。
swift-todo-2

続いて、iOS Application → Single View Application を選択して Next。
swift-todo-3

プロジェクト名などを入力します。
swift-todo-4

Product Name: TodoApp
Organization Name: 自分の名前や所属する組織名など
Organization Identifier: 所有するドメイン名を逆さにしたもの
Language: Swift
Devices: iPhone
use CoreData: チェック

Organization Name, Organization Identifier は任意に入力します。また Swift で開発するので Language は Swift を選択し、CoreData を使用するので use CoreData にもチェックを入れる。

プロジェクトの場所を選択して作成。
swift-todo-5

プロジェクトを保存する場所を選択します。Source Controle にチェックを入れて、「Create Git repository on My Mac」として Create をクリック。

以上で Xcode の新規プロジェクト作成は完了です。ここで一旦、Xcode を終了させておきます。

MagicalRecord のインストール

次に CocoaPods を使って MagicalRecord をインストールします。CocoaPods の使い方については以下を参照。
CocoaPodsの使い方、iOSライブラリの管理ツール | EasyRamble

MagicalRecord は、CoreData を Rails の ActiveRecord のように扱いやすくするライブラリです。CoreData は iOS 開発で sqlite などデータベースを使う際の OR マッパー的なフレームワークなのですが、そのままでは操作がやや煩雑ですので MagicalRecord を通して利用します。
MagicalRecordをSwiftで使う導入〜設定までの手順 | EasyRamble

コマンドラインから以下の手順で、CocoaPods で MagicalRecord をインストールします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
$ cd /path/to/XcodeProject/TodoApp
$ pod init
$ vi Podfile
platform :ios, '8.3'
target 'SwiftToDo' do
  pod 'MagicalRecord'
end
target 'SwiftToDoTests' do
end
$ pod install
 

TodoApp.xcworkspace が生成されますので、以降は Xcode でこれを利用するようにする。TodoApp.xcworkspace を Xcode で開きます。コンソールから開くには以下。

1
2
3
 
$ open TodoApp.xcworkspace
 

TodoApp.xcworkspace を開いて Xcode を起動しますと、ファイル・グループの横に ?(はてな)マークが付いています。
swift-todo-6

これは Git で add されていないものなので、Git の管理下にすれば ? マークが消える。Pods フォルダは MagicalRecord などライブラリが置かれるフォルダなので、Git 管理から除外します。

1
2
3
4
5
 
$ echo "Pods" >> .gitignore
$ git add .
$ git commit -m "pod install MagicalRecord"
 

以上の作業で、はてなマークが消えるはずです。以降説明には含めていませんが、作業の折り目で Git でコミットすると良いかと思います。Xcode の Source Control を使うと、GUI で Git の操作を行えます。私はコマンドラインのほうが慣れているので、コマンドで Git 操作しています。

【追記 2015/07/02】
Xcode を使った iOS 開発での .gitignore の詳細については、以下 Qiita の記事をご参照お願いします。

XCodeを使用する場合の.gitignoreの内容及び、その解説 – Qiita

上で説明したコマンドでは、私は Rails の gem 管理(/vendor/bundle 以下)と同じ感覚で、Pods ディレクトリを .gitignore に追加したのですが、Pods ディレクトリを git 管理するかどうかは、プロジェクトのワークフローによるそうです。

あと後日に、*.xccheckout というファイルが原因で、ブランチを merge できないという問題に遭遇しました。上記のエントリーを参考にして、*.xccheckout を .gitignore に含めたら問題なく merge できるようになりました。

なので、本格的な開発時には .gitignore を適切な内容にしておくことが必要かと思われます。
【追記ここまで】

Swift から MagicalRecord を使うための設定

次に Swift から MagicalRecord を利用するための設定です。MagicalRecord は Objective-C 製のライブラリなので、Swift から利用するためには、Bridging Header という設定を行う必要があります。まずは、Bridging Header 用のファイルを作成します。

TodoApp グループを右クリック → New File を選択。
swift-todo-7

iOS → Source → Header File を選択して Next。
swift-todo-8

ファイル名を TodoApp-Bridging-Header.h にして Create。
swift-todo-9

作成した TodoApp-Bridging-Header.h を以下の通りに編集します。

TodoApp-Bridging-Header.h

1
2
3
4
5
6
#ifndef TodoApp_TodoApp_Bridging_Header_h
#define TodoApp_TodoApp_Bridging_Header_h
 
#import "CoreData+MagicalRecord.h"
 
#endif

続いて、作成した TodoApp-Bridging-Header.h を Objective-C Bridging Header として利用できるように、ファイルへのパスを Xcode の指定の箇所で設定します。

TodoApp プロジェクトを選択 → Targets で TodoApp を選択 → Build Settings → All → Swift Compiler – Code Generation → Objective-C Bridging Header に先ほど作成した TodoApp-Bridging-Header.h のフルパスを入力します。
swift-todo-10

Objective-C Bridging Header の右横 TodoApp の下をダブルクリックすると、入力用フィールドが表示されます。
swift-todo-11

あるいは、Bridging Header の設定は以下ページの手順で行うと、若干簡略化されます。
Bridging Headerのファイル作成と設定を簡単に行う手順 | EasyRamble

続いて、MagicalRecord を利用するために、AppDelegate.swift を以下のように編集します。編集するメソッドは2つ。

AppDelegate.swift

1
2
3
4
5
6
7
8
9
10
func application ( application : UIApplication , didFinishLaunchingWithOptions launchOptions : [ NSObject : AnyObject ] ? ) -> Bool {
     // for magical record - initialize coredata
     MagicalRecord . setupCoreDataStackWithAutoMigratingSqliteStoreNamed ( "TodoApp.sqlite" )
     return true
}
 
func applicationWillTerminate ( application : UIApplication ) {
     // for magical record - clean up coredata
     MagicalRecord . cleanUp ( )
}

以上で、Swift から MagicalRecord を使うための設定は終了です。

以降、Storyboard を使って UI を作成していきます。

Todo リスト一覧の画面を作成する

Xcode で既に作成されている ViewController.swift を選択して、TodoListViewController.swift にリネームします。
swift-todo-12

  ↓

swift-todo-13

TodoListViewController.swift は、Todo リスト一覧画面のコントローラー用のファイルとなります。

ファイル名の変更に合わせて、クラス名も ViewController → TodoListViewController に変更。

TodoListViewController.swift(元の ViewController.swift)

1
2
3
class ViewController : UIViewController {
     // ...
}

  ↓

1
2
3
class TodoListViewController : UIViewController {
     // ...
}

続いて、Main.storyboard を選択して Storyboard を表示させます。

View Controller を選択して、Identity Inspector の Class を TodoListViewController に変更します。
swift-todo-14

次に、Todo List View Controller に Table View を配置していきます。

右下のオブジェクト・ライブラリの検索ボックスに「table」と入力して、Table View オブジェクトを選択します。
swift-todo-15

選択した Table View オブジェクトを、中央の Main.storyboard のエディタエリアの Todo List View Controller にドラッグ・アンド・ドロップする。
swift-todo-16

上下左右方向の中心を表すグリッド線が表示されるので、それを頼りに真ん中に Table View を配置します。上記のような位置になればOK。

次に Table View Cell オブジェクトを選択し、Table View の中にドラッグ・アンド・ドロップする。
swift-todo-17

上部に Prototype Cells という表示が現れます。

続いて、追加した Table View Cell オブジェクトに対応するクラスファイルを作成します。

Todo フォルダを選択して右クリック → New File。
swift-todo-19

iOS → Source → Cocoa Touch Class を選択して Next。
swift-todo-18

Subclass of をドロップダウンメニューから選び、Class の名前を入力します。
swift-todo-20

Class: TodoListItemTableViewCell
Subclass of: UITableViewCell
Language: Swift

として Next。

TodoApp の Group に作成。
swift-todo-21

上記画像のようになっていることを確認して Create。Table View のセルに表示する内容を色々と編集する場合は、ここで作成した TodoListItemTableViewCell.swift のファイルを編集します。今回はそのままです。

作成した TodoListItemTableViewCell クラスを、Storyboard 上の Table View Cell に割り当てます。Main.storyboard を開く。

Table View Cell を選択後、Identity inspector の Class に TodoListItemTableViewCell を選択。
swift-todo-22

同様に Attribute inspector の Identifier に TodoListItem と入力。
swift-todo-23

以上で、Todo List View Controller の中に Table View および Table View Cell を配置できました。

Table View の delegate と dataSource の設定

続いて、Table View を利用するために delegate と dataSource の設定を行います。View Controller から Table View を利用するためには、UITableViewDelegate プロトコルと UITableViewDataSource プロトコルを View Controller で継承して、プロトコルであらかじめ決められたメソッドを実装する必要があります。

まずは、Table View から delegate と dataSource を設定するために、Main.storyboard を開きます。

Table View を選択し Control キーを押しながら、Todo List View Controller にドラッグ・アンド・ドロップする。
swift-todo-24

以下画像のように表示されるので delegate を選択する。
swift-todo-25

同じ作業をもう一度繰り返し、dataSource を選択します。

続いて、TodoListViewController クラス に Table View の Outlet を作成します。Outlet は Storyboard 上のオブジェクトを、ソースコード上の変数として使えるようにするための仕組み(と理解しています)。Todo List View Controller を選択して、アシスタントエディタに TodoListViewController.swift を表示させる。

Table View を Control キーを押しながら、TodoListViewController クラスのソースコードにドラッグ・アンド・ドロップ。
swift-todo-26

Outlet の Name に tableView と入力。
swift-todo-27

Connection: Outlet
Name: tableView
Type: UITableView
Storage: Weak

として Connect ボタンをクリック。

TodoListViewController.swift のソースコード上では以下のようになりました。

TodoListViewController.swift

1
2
3
4
5
6
class TodoListViewController : UIViewController {
 
     @ IBOutlet weak var tableView : UITableView !
     override func viewDidLoad ( ) {
         // ...
}

ここまでの作業で、Table View の Connections inspector が次のとおりになっていることを確認する。
swift-todo-28

TodoListViewController.swift を開いて、UITableViewDelegate, UITableViewDataSource を使用(継承)することをソースコードにも追加します。

TodoListViewController.swift

1
2
3
4
5
6
class TodoListViewController : UIViewController {
 
     @ IBOutlet weak var tableView : UITableView !
    
     // ...
}

  ↓

1
2
3
4
5
6
class TodoListViewController : UIViewController , UITableViewDelegate , UITableViewDataSource {
 
     @ IBOutlet weak var tableView : UITableView !
    
     // ...
}

TodoListViewController.swift に UITableViewDelegate, UITableViewDataSource の継承を追記すると、エラーが表示されるかと思います。
swift-todo-29

1
2
3
 
Type 'TodoListViewController' does not conform to protocol 'UITableViewDataSource'
 

これは UITableViewDataSource の protocol 継承で、実装すべきメソッドを実装していないのが原因です。とりあえず、先に Storyboard での UI 作りを先に終えたいので、これらのメソッドの実装は後に回します。

Navigation Controller の追加と Navigation Item の設定

画面遷移のための Navigation Controller を追加します。Main.storyboard を開く。

Todo List View Controller を選択した状態で、上部メニューの「Editor → Embed In → Navigation Controller」をクリックして、Navigation Controller を選択。
swift-todo-30

Storyboard エディタエリアが以下の状態になります。
swift-todo-31

Todo List View Controller → Navigation Item を選択し、Attributes Inspector の Title に「Todo List」と入力。
swift-todo-32

Navigation Item の表示が Todo List に変わり、また Todo List View Controller の上部に Todo List とタイトルが表示される。
swift-todo-33

次に、新しいタスクを追加する時に押すための + ボタンを作ります。右下オブジェクト・ライブラリの検索ボックスに「bar button」と入力して Bar Button Item を選択。

Bar Button Item を Todo List(Navigation Item)の右端(バッテリー表示のすぐ下)にドラッグ・アンド・ドロップ。
swift-todo-34

Bar Button Item を選択した状態で、Attributes Inspector の Identifier を Add に変更。
swift-todo-35

表示が Item から + に変わったのを確認します。
swift-todo-36

Todo タスク追加の画面を作成する

次に、Todo リスト一覧の画面の +(Add)ボタン(Bar Button Item)を押した後に遷移する、Todo タスク追加の画面を作成していきます。この画面は後で作成する、Todo 詳細&編集画面と共通のビューとなります。

Main.storyboard でオブジェクト・ライブラリから View Controller を見つけて、Storyboard にドラッグ・アンド・ドロップ。
swift-todo-37

Todo List View Controller の「+ボタン」を選択して、Control キーを押しながら、追加した View Controller の上にドラッグ・アンド・ドロップします。
swift-todo-38

Action Segue の show を選択。
swift-todo-39

Todo List View Controller と View Controller が + ボタンを介してつながりました。
swift-todo-40

オブジェクト・ライブラリから Navigation Item を View Controller にドラッグ・アンド・ドロップ。
swift-todo-41

Navigation Item(Title)を選択し、Attributes inspector で Title を「Todo Item」に変更。
swift-todo-42

Bar Button Item を Todo Item の左端にドラッグ・アンド・ドロップして、Identifier を Cancel に変更。
swift-todo-43

同様に Bar Button Item を Todo Item の右端にドラッグ・アンド・ドロップして、Identifier を Save に変更。
swift-todo-44

この Save ボタンが Todo タスクを追加して保存するためのボタンとなります。続いて、Todo タスクを文字で入力するためのフィールドを作る。

オブジェクト・ライブラリから Text Field を View Controller(Todo Item)にドラッグ・アンド・ドロップ。
swift-todo-45

Text Field のサイズと位置は適当に調整しておきます。

ここで、Auto Layout の設定を行いますが、今回は Xcode が提案する Auto Layout の自動設定を行います。1つずつの部品に対して、細かく Auto Layout を手動で設定することもできますが、このチュートリアルでは Auto Layout の詳細には触れません。Auto Layout の詳細については、冒頭で紹介したドットインストールを参照。

Todo List View Controller(Todo 一覧リスト)を選択した状態で、Editor → Resolve Auto Layout → Reset to Suggested Constraints をクリックします。
swift-todo-46

Todo タスク追加/詳細ページ用の View Controller(Title)についても同じ作業を行う。

続いて、Todo タスク追加/詳細ページの View Controller に対応する TodoItemViewController.swift ファイルを作成します。

TodoApp グループから New File。
swift-todo-47

iOS → Source → Cocoa Touch Class を選択して Next。
swift-todo-48

UIViewController のサブクラスとして、TodoItemViewController クラスを作成します。
swift-todo-49

TodoApp グループに Create。
swift-todo-50

Main.storyboard を選択して、Todo タスク追加/詳細ページ View Controller の Identity inspector で、Class に TodoItemViewController を指定する。
swift-todo-51

Cancel, Save ボタンの Action と Text Field の Outlet を作成

Main.storyboard で Todo Item の View Controller を選択し Asistant Editor を開く。Cancel, Save ボタンが押された時に対応する action を設定します。

Cancel ボタンを、Control キーを押しながら TodoItemViewController のソースコードにドラッグ・アンド・ドロップ。
swift-todo-52

cancel という名前の Action を作成。
swift-todo-53

Connection: Action
Name: cancel
Type: UIBarButtonItem

として、Connect ボタンをクリック。

同様に Save ボタンを、Control キーを押しながら TodoItemViewController にドラッグ・アンド・ドロップ。
swift-todo-54

save という名前の Action を作成。
swift-todo-55

Connection: Action
Name: save
Type: UIBarButtonItem

として、Connect ボタンをクリック。

TodoItemViewController.swift に追加された @IBAction で始まる行を確認して、コードを以下のように編集します

TodoItemViewController.swift

1
2
3
4
5
6
7
@ IBAction func cancel ( sender : UIBarButtonItem ) {
     navigationController ! . popViewControllerAnimated ( true )
}
 
@ IBAction func save ( sender : UIBarButtonItem ) {
     navigationController ! . popViewControllerAnimated ( true )
}

各々 Cancel, Save ボタンが押された時のアクションを実装するメソッドとなります。ここでは、簡易的に popViewControllerAnimated で1つ前の画面に戻るように実装しています。実際にキャンセルや保存を行う実装は後で行います。

Todo Item の View Controller の Connections inspector で Received Actions(画像一番下)が設定されていることを確認。
swift-todo-56

続いて、文字の入力フィールドである Text Field の Outlet の設定を行います。Main.storyboard で Asistant Editor を開く。

Text Field を Control キーを押しながら、TodoItemViewController クラスの画像の位置にドラッグ・アンド・ドロップ。
swift-todo-57

todoField という名前の Outlet を作成。
swift-todo-58

Connection: Outlet
Name: todoField
Type: UITextField
Storage: Weak

として Connect。

TodoItemViewController.swift

1
@ IBOutlet weak var todoField : UITextField !

が追加されたのを確認します。これで、Text Field の Outlet を作成できました。

Todo タスク用のモデルを作成

Todo タスク用モデルで利用する CoreData のエンティティを作成します。CoreData のエンティティとは、RDBMS でいうテーブルのような概念っぽい。

TodoApp.xcdatamodeld を選択し、下記の画像のようにエンティティを作成。
swift-todo-59

Entitiy: Todo
Attribute: item
Type: String

下部の Add Entitiy をクリックして追加。名前を Todo にする。また Attributes の下の + をクリックして属性を追加、名前は item で、型は String を指定。

続いて、モデル用のファイルを作成します。

TodoApp.xcdatamodeld を選択した状態で、Editor → Create NSManagedObject Subclass をクリック。
swift-todo-60

TodoApp にチェックして Next。
swift-todo-61

Todo にチェックして Next。
swift-todo-62

TodoApp グループに Create。
swift-todo-63

Todo.swift が作成されたことを確認し、@objc(Todo) の行を追加します。

Todo.swift

1
2
3
4
5
6
7
8
9
import Foundation
import CoreData
 
@ objc ( Todo )
class Todo : NSManagedObject {
 
     @ NSManaged var item : String
 
}

TodoApp.xcdatamodeld を選択し、Data Model inspector で Name を Todo、Class を Todo に変更します。
swift-todo-64

一連の作業で作成した CoreData のモデル(Todo モデル)に対して、MagicalRecord を使って CRUD 操作を行うことになります。

UITableViewDelegate, UITableViewDataSource のメソッドを実装

ここで、エラーを放置していた TodoListViewController.swift で、UITableViewDelegate, UITableViewDataSource のメソッド、および保存済みのタスク一覧を取得する処理を実装する。

TodoListViewController.swift を以下のように編集します。

TodoListViewController.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import UIKit
import CoreData
 
class TodoListViewController : UIViewController , UITableViewDelegate , UITableViewDataSource {
 
     @ IBOutlet weak var tableView : UITableView !
     var todoEntities : [ Todo ] !
    
     override func viewDidLoad ( ) {
         super . viewDidLoad ( )
         todoEntities = Todo . MR_findAll ( ) as ? [ Todo ]
     }
 
     override func didReceiveMemoryWarning ( ) {
         super . didReceiveMemoryWarning ( )
         // Dispose of any resources that can be recreated.
     }
    
     func tableView ( tableView : UITableView , numberOfRowsInSection section : Int ) -> Int {
         return todoEntities . count
     }
    
     func tableView ( tableView : UITableView , cellForRowAtIndexPath indexPath : NSIndexPath ) -> UITableViewCell {
         let cell = tableView . dequeueReusableCellWithIdentifier ( "TodoListItem" ) as ! UITableViewCell
         cell . textLabel ! . text = todoEntities [ indexPath . row ] . item
         return cell
     }
}

import CoreData で CoreData を使うことを宣言。todoEntities というプロパティに、Todo モデルのインスタンスを配列として保持するようにしています。

viewDidLoad() メソッドでは、MagicalRecord の MR_findAll() メソッドを使って、Todo をすべて読み込んでいます。これで Todo リストの一覧を取得する。

追加した2つの tableView メソッドは、UITableViewDataSource 継承により実装しなければならないメソッドです。各々、セクションに含まれる行数を返すメソッド、およびセルに表示する内容を設定してセルを返すメソッドとなります。これらのメソッドを実装することで、表示されていたエラーが消えるはずです。

動作確認のためにビルドしてみる

ここで一旦ビルドを実行してみましょう。Xcode 左上部の三角マークをクリックします。
swift-todo-65

「Do you want the application “Xcode.app” to accept incoming network connections?」とダイアログボックスが表示されたら、Allow をクリックします。

シミュレーターが起動して動作を確認できる。Todo List 画面。
swift-todo-66

+ ボタンをタップすると、Todo Item 画面に遷移。
swift-todo-67

Todo List のページで + ボタンをクリックすると、Todo Item のページに移動し、Cancel または Save を押すと元の Todo List のページに戻ることが確認できます。

まだ必要な実装を行っていないため、実際のタスク追加・編集・削除などは動作しない状態です。

Todo タスクを追加できるようにメソッドを実装

Todo タスクを保存できるようにするために、TodoItemViewController.swift の save メソッドを実装する。Todo 追加画面で Text Field にタスクを入力後、Save ボタンが押された時に実行されるメソッドです。

TodoItemViewController.swift の save メソッドを以下のように編集。

TodoItemViewController.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
import UIKit
import CoreData
 
class TodoItemViewController : UIViewController {
     // ...
 
     @ IBAction func save ( sender : UIBarButtonItem ) {
         let newTask : Todo = Todo . MR_createEntity ( ) as ! Todo
         newTask . item = todoField . text
         newTask . managedObjectContext ! . MR_saveToPersistentStoreAndWait ( )
         navigationController ! . popViewControllerAnimated ( true )
     }
}

MagicalRecord の MR_createEntity() メソッドで新たなタスクを作成し、Text Field の入力文字を設定した後、MR_saveToPersistentStoreAndWait() メソッドで、新たに作られたタスクを保存しています。

また、TodoListViewController.swift に viewWillAppear メソッドを追加します。

TodoListViewController.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class TodoListViewController : UIViewController , UITableViewDelegate , UITableViewDataSource {
 
     @ IBOutlet weak var tableView : UITableView !
     var todoEntities : [ Todo ] !
    
     override func viewWillAppear ( animated : Bool ) {
         super . viewWillAppear ( animated )
         todoEntities = Todo . MR_findAll ( ) as ? [ Todo ]
        tableView . reloadData ( )
     }
 
     override func viewDidLoad ( ) {
         super . viewDidLoad ( )
         todoEntities = Todo . MR_findAll ( ) as ? [ Todo ]
     }
 
     // ...
}

viewWillAppear() では、viewDidLoad() と同様に Todo タスク全一覧を取得しています。

ここで動作確認のためにビルド実行しましょう。Todo List 一覧画面で、右上の + ボタンからタスクが追加できるようになりました。
swift-todo-68

タスクを入力して Save ボタンを押すと、Todo List 画面に反映されます。いくつかタスクを追加した後の Todo List 画面。
swift-todo-69

スワイプで Todo タスクを削除できるようにする

次に Todo List の画面でスワイプで、保存済みの Todo タスクを削除できるようにします。

TodoListViewController.swift に以下のとおりメソッドを追加。

TodoListViewController.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
class TodoListViewController : UIViewController , UITableViewDelegate , UITableViewDataSource {
     // ...
 
     func tableView ( tableView : UITableView , commitEditingStyle editingStyle : UITableViewCellEditingStyle , forRowAtIndexPath indexPath : NSIndexPath ) {
         if editingStyle == . Delete {
             todoEntities . removeAtIndex ( indexPath . row ) . MR_deleteEntity ( )
             NSManagedObjectContext . MR_defaultContext ( ) . MR_saveToPersistentStoreAndWait ( )
             tableView . reloadData ( )
         }
     }
 
     // ...
}

MagicalRecord の MR_deleteEntity() メソッドで、Todo タスクを削除するようにしています。

確認のためにビルド実行。

Todo List 画面で、アイテムをスワイプすると以下のように Delete ボタンが表示され削除できます。
swift-todo-70

Todo List 一覧 → Todo Item の詳細&編集への画面遷移

続いて、Todo List 一覧画面 → Todo Item の詳細&編集画面に移動できるようにします。Todo Item の詳細&編集画面は、タスク追加の画面と共通です。Main.storyboard を開きます。

TodoListItem(Table View Cell)を選択し Control キーを押しながら、Todo Item の View Controller にドラッグ・アンド・ドロップ。
swift-todo-71

Selection Segue で show を選択。
swift-todo-72

TodoListItem → Todo Item の矢印を選択し、その Attributes inspector で Identifier に edit と入力します。
swift-todo-73

edit は画面遷移を識別するための識別子となります。これで、Prototype Cells(Todo List 一覧画面のテーブルのセル)→ Todo Item(Todo 詳細&編集画面)がつながりました。

TodoListViewController.swift に、画面遷移のための以下のメソッドを追加。

TodoListViewController.swift

1
2
3
4
5
6
7
8
9
10
11
class TodoListViewController : UIViewController , UITableViewDelegate , UITableViewDataSource {
     // ...
 
     override func prepareForSegue ( segue : UIStoryboardSegue , sender : AnyObject ? ) {
         if segue . identifier == "edit" {
             let todoController = segue . destinationViewController as ! TodoItemViewController
             let task = todoEntities [ tableView . indexPathForSelectedRow ( ) ! . row ]
            todoController . task = task
         }
     }
}

edit の識別子を持つ segue(画面遷移)が選択された時のアクションとなります。Todo List 画面で選択された(タップされた)タスクを、TodoItemViewController の task プロパティに設定しています。

続いて TodoItemViewController.swift を編集して、task プロパティを追加。

TodoItemViewController.swift

1
2
3
4
5
6
7
class TodoItemViewController : UIViewController {
 
     @ IBOutlet weak var todoField : UITextField !
     var task : Todo ? = nil
 
     // ...
}

task プロパティは、Todo のオプショナル型の変数にします。

ビルド実行。

Todo List 画面でタスクををタップすると…
swift-todo-74

Todo Item に移動できるようになりました。
swift-todo-75

しかし、Todo Item に何も表示されていない状態ですので、Todo List でタップされたタスクを Text Field 内に表示させるようにしてみます。

Todo Item の Text Field に選択されたタスクを表示

TodoItemViewController.swift の viewDidLoad() メソッドを編集します。

TodoItemViewController.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class TodoItemViewController : UIViewController {
 
     @ IBOutlet weak var todoField : UITextField !
     var task : Todo ? = nil
    
     override func viewDidLoad ( ) {
         super . viewDidLoad ( )
         if let taskTodo = task {
             todoField . text = taskTodo . item
         }
     }
 
     // ...
}

ビルド実行。

これで Todo List 画面でタスクをタップすると…
swift-todo-76

Todo Item 画面の Text Field 内にタスク詳細が表示されるようになりました。
swift-todo-77

Todo タスクを編集できるようにする

続いて、Todo Item 画面で既存のタスクを編集できるようにします。TodoItemViewController.swift の save() アクションを以下のように変更します。

TodoItemViewController.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class TodoItemViewController : UIViewController {
     // ...
 
     @ IBAction func save ( sender : UIBarButtonItem ) {
         if task != nil {
             editTask ( )
         } else {
             createTask ( )
         }
         navigationController ! . popViewControllerAnimated ( true )
     }
    
     func createTask ( ) {
         let newTask : Todo = Todo . MR_createEntity ( ) as ! Todo
         newTask . item = todoField . text
         newTask . managedObjectContext ! . MR_saveToPersistentStoreAndWait ( )
     }
    
     func editTask ( ) {
         task ? . item = todoField . text
         task ? . managedObjectContext ! . MR_saveToPersistentStoreAndWait ( )
     }
}

task プロパティが空の時(既存タスクが存在しない)時は createTask() 呼び出しでタスクを新規作成、task プロパティが存在する(既存タスクが存在する)時は editTask() 呼び出しで編集するように変更しました。

また TodoListViewController.swift に controllerDidChangeContent() メソッドを追加。

TodoListViewController.swift

1
2
3
4
5
6
7
class TodoListViewController : UIViewController , UITableViewDelegate , UITableViewDataSource {
     // ...
 
     func controllerDidChangeContent ( controller : NSFetchedResultsController ) {
         tableView . reloadData ( )
     }
}

ビルド実行。

以下画像のように、Todo Item 画面で既存のタスクを編集できるようになりました。

Todo List 画面で「buy a swift book」のタスクをタップして…
swift-todo-78

Todo Item 画面で「read a swift book」に変更して save。
swift-todo-79

Todo List 画面に変更が反映されました。
swift-todo-80

以上で Todo アプリの機能は作り終えました。長かった Swift を用いた Todo アプリ開発チュートリアルは終了です。おつかれさまでした!

冒頭でもお伝えしたとおり、私は Swift/iOS 開発歴がまだ1ヶ月程度の入門者です。もし間違っている箇所がありましたら、ご指摘頂けるとありがたく思います。よろしくお願いいたします。

この開発チュートリアルを作るにあたり、以下のウェブページを参考にさせて頂きました。ありがとうございました。
iOS Swift Tutorial: Core Data with MagicalRecord in Swift – James Leist
CoreData tutoiral in Swift using NSFetchedResultsController Ramblings on Swift
Bundlr – SwiftとMagicalRecordを使って簡単なTodoアプリを作るチュートリアル – Qiita
CocoaDocs.org – MagicalRecord Reference

遭遇したエラー達

最後にこの Todo アプリを作っていた時に遭遇したエラーを挙げて、その解決法を記しておきます。

・libc++abi.dylib: terminating with uncaught exception of type NSException

原因: モデルのファイルで @objc の宣言忘れ

Todo.swift

1
2
3
4
5
6
7
8
9
import Foundation
import CoreData
 
@ objc ( Todo )
class Todo : NSManagedObject {
 
     @ NSManaged var item : String
 
}

のように @objc(Todo) の行を追加することで解決できました。


转载于:https://my.oschina.net/u/587148/blog/511921

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值