接下來,進行台股申購 Model 實作,這個 Model 該負責的任務如下
程式碼如下
//
// StockSubscriptionModel.swift
// ITIronMan
//
// Created by Marvin on 2021/9/4.
//
import Foundation
protocol StockSubscriptionModelDelegate: AnyObject {
func didRecieveList(_ subscriptionList: [StockSubscriptionInfo], error: Error?)
}
/// 股票申購 VC 所需的 Model
class StockSubscriptionModel {
weak var delegate: StockSubscriptionModelDelegate?
var subscriptionList = [StockSubscriptionInfo]()
private lazy var manager: StockSubscriptionManager = {
return StockSubscriptionManager()
}()
var count: Int {
return subscriptionList.count
}
func getSubscriptionInfo(at indexPath: IndexPath) -> StockSubscriptionInfo? {
let index = indexPath.row
if subscriptionList.indices.contains(index) {
return subscriptionList[index]
}
return nil
}
func requestStockSubscription() {
let year = 2021
manager.requestStockSubscriptionInfo(year: year) { [weak self] subscriptionList, error in
self?.subscriptionList = subscriptionList
self?.delegate?.didRecieveList(subscriptionList, error: error)
}
}
}
要呈現的資料,先大概設計裝載下列資訊
簡單拉一個 UITableViewCell
然後 VC 負責把 View 和 Model 連結起來,程式碼如下
//
// StockSubscriptionViewController.swift
// ITIronMan
//
// Created by Marvin on 2021/9/4.
//
import UIKit
class StockSubscriptionViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
private lazy var model: StockSubscriptionModel = {
let model = StockSubscriptionModel()
model.delegate = self
return model
}()
// MARK: - life cycle
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
}
// MARK: - private methods
private func setupUI() {
tableView.dataSource = self
tableView.delegate = self
}
// MARK: - IBAction
@IBAction func requestSubscriptionButtonDidTap(_ sender: Any) {
model.requestStockSubscription()
}
}
extension StockSubscriptionViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: StockSubscriptionTableViewCell.identifier, for: indexPath) as? StockSubscriptionTableViewCell,
let info = model.getSubscriptionInfo(at: indexPath) else {
return UITableViewCell()
}
let state = "申購狀態"
let firstSection = "\(info.stockName) - (\(info.stockCode))"
let secondSection = "申購股數: \(info.stockCountString)"
let thirdSection = "申購價: \(info.actualPrice)"
let forthSection = "中籤率: \(info.subscriptionRateString) %"
cell.stateLabel.text = state
cell.firstSectionLabel.text = firstSection
cell.secondSectionLabel.text = secondSection
cell.thirdSectionLabel.text = thirdSection
cell.forthSectionLabel.text = forthSection
return cell
}
}
extension StockSubscriptionViewController: StockSubscriptionModelDelegate {
func didRecieveList(_ subscriptionList: [StockSubscriptionInfo], error: Error?) {
if let error = error {
print("you got error during subscriptions request: \(error.localizedDescription)")
return
}
tableView.reloadData()
}
}
基本的 UI 大致如下
不過還差一點,因為這個申購資訊包含了一般人不會感興趣的央債,市面上常用的下單軟體,都會把央債去掉,而這一部分的職責,應該是 Model 要處理。當 Model 在接收到 StockSubscriptionManager 傳過來的資料時,會 filter 掉央債,再通知 VC。
在 model 內加上一個 private func 做去除。股票代號的前幾碼是有意義的,舉例來說 00 開頭一定是 ETF,11 開頭一定是水泥類股,12 開頭一定是食品類股。
而央債的開頭第一個字母是 A,我們可以用這個規則,把央債去掉。
private func filterNotAvailable(_ subscriptionList: [StockSubscriptionInfo]) -> [StockSubscriptionInfo] {
let list = subscriptionList.filter { info in
let code = info.stockCode
let firstCharacter = code.first ?? "0"
return firstCharacter != "A"
}
return list
}
然後在收到申購列表後,進行清除,所以 func requestStockSubscription() 要改成這樣。
func requestStockSubscription() {
let year = 2021
manager.requestStockSubscriptionInfo(year: year) { [weak self] subscriptionList, error in
// 需要去掉中央債的資料
self?.subscriptionList = self?.filterNotAvailable(subscriptionList) ?? []
self?.delegate?.didRecieveList(subscriptionList, error: error)
}
}
這樣,你的列表中就不會有央債的資料了
下一篇,介紹 TableViewCell 最左邊的 [申購狀態] 處理,下一篇會用到大量的 Date 相關 API。