[iOS] Todoアプリを作りたい

2015/02/12

こんにちは。きんくまです。

BackboneのModelの機能限定のライブラリBBModelをせっかく書いたので、ここはやっぱりTodoリストだよね!と思い、作ってみました。

bbmodel_todo

githubにソースは全部アップしました。

>> BBModelTodo

TodoとTodos

やることとそのコレクションです。

class Todo: Model {
    
    var title:String?{
        get{ return self.get("title") as? String }
        set{ self.set("title", newValue!) }
    }
    
    var done:Bool{
        get{
            let aDone:Bool? = self.get("done") as? Bool
            return aDone ?? false
        }
        set{ self.set("done", newValue)}
    }
    
    override init(attributes: [String : Any]? = nil) {
        super.init(attributes: attributes)
        self.done = false
    }
    
    func toggle(){
        self.done = !self.done
    }
}

class Todos: Collection {

    override init(models: [Model]?, options: [String : Any]?) {
        super.init(models: models, options: options)
        self.model = Todo.self
    }
    
    func getCompletedTodos()->[Todo]{
        var completedTodos = [Todo]()
        for aTodo in self.models {
            let todo = aTodo as Todo
            if todo.done {
                completedTodos.append(todo)
            }
        }
        return completedTodos
    }
}

メインのViewConroller

Todoが追加、削除されるイベントのコールバックで、セルも追加、削除しています。

プロトコルごとにExtension作っているのは前にここのソース読んでたときにそうやってたからなんだけど、これが一般的なのかどうかは知らんです。

class ViewController: UIViewController {
    @IBOutlet weak var inputTextField:UITextField!
    @IBOutlet weak var todoListTableView:UITableView!
    @IBOutlet weak var clearButton:UIButton!
    private var todoListTableViewTapGesture:UITapGestureRecognizer!
    
    private var _todos:Todos = Todos(models: nil, options: nil)

    override func viewDidLoad() {
        super.viewDidLoad()
        todoListTableViewTapGesture = UITapGestureRecognizer(target: self, action: "onTodoListTableViewTap")
        todoListTableViewTapGesture.cancelsTouchesInView = false
        todoListTableView.addGestureRecognizer(todoListTableViewTapGesture)
        
        inputTextField.delegate = self
        
        self._todos.on(Collection.events.ADD) {
            [unowned self](model, collection, options) in
            let addIndexPath = NSIndexPath(forRow: collection.length - 1, inSection: 0)
            self.todoListTableView.insertRowsAtIndexPaths([addIndexPath],
                withRowAnimation: UITableViewRowAnimation.Automatic)
            self.todoListTableView.scrollToRowAtIndexPath(addIndexPath, atScrollPosition: UITableViewScrollPosition.Top, animated: true)
        }
        
        self._todos.on(Collection.events.REMOVE) {
            [unowned self](model, collection, options:[String:Any]?) in
            let removeIndex = options?["index"] as Int
            let removeIndexPath = NSIndexPath(forRow: removeIndex, inSection: 0)
            self.todoListTableView.deleteRowsAtIndexPaths([removeIndexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
        inputTextField.resignFirstResponder()
    }

    @IBAction func onClearButtonTap(){
        let completedTodos = self._todos.getCompletedTodos()
        self._todos.remove(completedTodos)
    }
    
    func onTodoListTableViewTap(){
        self.inputTextField.resignFirstResponder()
    }
}

extension ViewController: UITableViewDataSource, UITableViewDelegate{
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return _todos.length
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell:TodoViewCell? = tableView.dequeueReusableCellWithIdentifier("TodoViewCell", forIndexPath: indexPath) as? TodoViewCell
        cell?.setup()
        let todo:Todo = _todos.at(indexPath.row) as Todo
        cell?.updateView(todo)
        return cell!
    }
    
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        self.inputTextField.resignFirstResponder()
        
        var cell:TodoViewCell? = tableView.cellForRowAtIndexPath(indexPath) as? TodoViewCell
        if let aCell = cell {
            var todo:Todo = _todos.at(indexPath.row) as Todo
            todo.toggle()
            aCell.updateView(todo)
            aCell.selected = false
        }
    }
}

extension ViewController: UITextFieldDelegate{
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        let text = textField.text
        if let aText = text {
            if countElements(aText) > 0 {
                let todo = Todo()
                todo.title = aText
                self._todos.add(todo)
                textField.text = ""
                textField.resignFirstResponder()
            }
        }
        return true
    }
}
LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る