[Swift/iOS] フリックで更新するTableView

SNSのアプリなどでおなじみのタイムラインを下にフリックしてテーブルを更新させるためのコードです。

例として1から6までの数字が並んだテーブルがフリックする度に数字が2倍されていくというものを作ります。
この2倍する処理がネットワーク経由でデータを更新する処理だと思ってください。


UI部品の配置

  • デフォルトのViewの中にTableViewを追加
  • TableViewの中にTableViewCellを追加
  • TableViewCellの中にLabelを追加

TableViewCellの設定

  • UITableViewCellを継承した新しいクラス(NumberCell)を追加
  • TableViewCellのIdentity Inspector→Custom Class→ClassにNumberCellを指定
  • Attribute Inspector→Table View Cell→Identifierに識別子(numberCell)を指定
  • Labelにカーソルを合わせてCtrlキーを押しながらNumberCellにドラッグしコネクションを設定

import Foundation
import UIKit

class NumberCell: UITableViewCell {
    
    @IBOutlet weak var label: UILabel!    
}

Labelの設定

  • Labelの上下左右にスペースのConstraintを設定

ViewControllerの設定

  • UITableViewDataSourceとUITableViewDelegateを継承
  • UITableViewDataSourceとUITableViewDelegateの必須メソッドを実装
  • UIRefreshControlオブジェクトを生成しUIRefreshControl.addTarget()でスワイプ時に呼ぶメソッド(refresh)を指定
  • refreshControlオブジェクトをaddSubview()でTableViewにサブビューとして追加
  • refreshを実装。必ずUIRefreshControl.endRefreshing()を呼ぶ
import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
    @IBOutlet weak var tableView: UITableView!
    
    var numberList:[Int] = [1, 2, 3, 4, 5, 6]
    var refreshControl:UIRefreshControl!
    let semaphore = DispatchSemaphore(value: 1)

    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.delegate = self
        tableView.dataSource = self
        
        refreshControl = UIRefreshControl()
        refreshControl.attributedTitle = NSAttributedString(string: "再読み込み中")
        refreshControl.addTarget(self, action: #selector(ViewController.refresh), for: UIControlEvents.valueChanged)
        tableView.addSubview(refreshControl)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    func updateTable () {
        //時間がかかる処理と想定してグローバルキューで実行
        DispatchQueue.global().async {
            
            for (i, num) in self.numberList.enumerated() {
                self.numberList[i] = num * 2
            }
            DispatchQueue.main.async {
                // UI更新はメインスレッドで実行
                self.tableView.reloadData()
                self.semaphore.signal()
            }
        }
    }
    
    //UIRefreshControl によって画面を縦にフリックしたあとに呼ばれる
    @objc func refresh() {
        updateTable()
        // 別スレッドでの処理が終了するのを待つ
        semaphore.wait()
        semaphore.signal()
        //この処理の前にbeginRefreshingが呼ばれているはずなので終了する
        refreshControl.endRefreshing()
    }
    
    //UITableViewDataSourceプロトコルの必須メソッド
    //テーブルの行数を返す
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return numberList.count
    }
    
    //UITableViewDataSourceプロトコルの必須メソッド
    //指定行のセルデータを返す
    internal func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "numberCell", for: indexPath) as? NumberCell else {
            return UITableViewCell()
        }
        cell.label.text = String(numberList[indexPath.row])
        return cell
    }
    
    //UITableViewDelegateプロトコルの必須メソッド
    //行をタップされたときに呼ばれる
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath:IndexPath) {
        print(numberList[indexPath.row])
    }
}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です