iT邦幫忙

2021 iThome 鐵人賽

DAY 10
0
Mobile Development

使用 Swift 和公開資訊,打造投資理財的 Apps系列 第 10

D10- 用 Swift 和公開資訊,打造投資理財的 Apps { 台股申購實作.3-讓申購資訊放進可以清楚理解的 TableView }

接下來,進行台股申購 Model 實作,這個 Model 該負責的任務如下

  • 申購資料下載
  • 申購列表總共數量
  • 第 n 個列表是哪個申購資訊?

程式碼如下

//
//  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

https://ithelp.ithome.com.tw/upload/images/20210919/20140622cbtI2JgmPl.png

然後 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 大致如下

https://ithelp.ithome.com.tw/upload/images/20210919/201406229i9lBgNyjF.png

不過還差一點,因為這個申購資訊包含了一般人不會感興趣的央債,市面上常用的下單軟體,都會把央債去掉,而這一部分的職責,應該是 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)
        }
    }

這樣,你的列表中就不會有央債的資料了

https://ithelp.ithome.com.tw/upload/images/20210919/20140622FlcfTtf1D1.png

下一篇,介紹 TableViewCell 最左邊的 [申購狀態] 處理,下一篇會用到大量的 Date 相關 API。


上一篇
D9-用 Swift 和公開資訊,打造投資理財的 Apps { 台股申購實作.2 -讀取Big5碼的csv}
下一篇
D11-用 Swift 和公開資訊,打造投資理財的 Apps { 台股申購實作.4 - 用 Calendar 物件處理台灣的民國年}
系列文
使用 Swift 和公開資訊,打造投資理財的 Apps37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言