处理申购 VC 的资料,是由 StockSubscriptionModel 处理的。
在前面,我们在 AppDelegate 的 didFinishLaunch 下载了台股上市收盘资料,并存在 UserDefaults 内,所以这个 model 在 init 的时候,理论上就可以拿到上市收盘资料了,如果没有,那你可以在这个时机点再发动一次下载。
注: 这边有优化空间,但更细腻的操作,就留待读者在实务上各自发挥
1-选择存放资料结构
在 StockSubscriptionModel 中,可以放日收的结构有 Array, Dictionary。这边我选择了 Dictionary,并把股票代号当成 key 值,value 为日收的 data model - StockDayTick。
2-实作
先在 StockSubscriptionModel 加上 key vs. value 的 property
private var twMarketDayTicks: [String: StockDayTick] = [:]
再加上日收的 manager,而且有要从 String 转成 NSNumber, Double 的地方,所以也要一个 NumberFormatter
private lazy var dayPriceManager: StockDayPriceManager = {
return StockDayPriceManager()
}()
private lazy var numberFormatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
return formatter
}()
在 Model 一开始,就把上市日收从 UserDefaults 中拿出,并存起来
init() {
setupDayTicks()
}
// MARK: - private func
// 将 UserDefaults 中的 day ticks 拿出,并把 stockCode 当 key 值
private func setupDayTicks() {
let dayTicks = dayPriceManager.getTwAllStockDayPriceFromUserDefaults()
let keys = dayTicks.map { tick in
return tick.stockCode
}
for (index, tick) in dayTicks.enumerated() {
let key = keys[index]
self.twMarketDayTicks[key] = tick
}
}
然後做出让 VC 呼叫的接口,当 VC 把 subscription 输入,就可以得到价差的 String
/// 命名可以用 rename 改得更符合变数意义,请自行变更
func getPricePercentDifferenctString(subscription: StockSubscriptionInfo) -> String? {
let code = subscription.stockCode
let subscriptionPrice = subscription.price
if let tick = getTick(from: code),
let subscriptionPriceDouble = numberFormatter.number(from: subscriptionPrice)?.doubleValue,
let closePrice = tick.close {
let percentage = (closePrice - subscriptionPriceDouble) / subscriptionPriceDouble
let string = String(format: "%.1f", percentage * 100)
return string
}
return nil
}
整个 Model 的 Code
//
// 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 var twMarketDayTicks: [String: StockDayTick] = [:]
private lazy var subscriptionManager: StockSubscriptionManager = {
return StockSubscriptionManager()
}()
private lazy var dayPriceManager: StockDayPriceManager = {
return StockDayPriceManager()
}()
private lazy var numberFormatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
return formatter
}()
var count: Int {
return subscriptionList.count
}
init() {
setupDayTicks()
}
// MARK: - private func
// 将 UserDefaults 中的 day ticks 拿出,并把 stockCode 当 key 值
private func setupDayTicks() {
let dayTicks = dayPriceManager.getTwAllStockDayPriceFromUserDefaults()
let keys = dayTicks.map { tick in
return tick.stockCode
}
for (index, tick) in dayTicks.enumerated() {
let key = keys[index]
self.twMarketDayTicks[key] = tick
}
}
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
}
private func getQueryYear() -> Int {
let dateUtility = DateUtility()
return dateUtility.getIntFromDate(component: .year)
}
private func getTick(from stockCode: String) -> StockDayTick? {
if let tick = twMarketDayTicks[stockCode] {
return tick
}
return nil
}
// MARK: - public func
func getSubscriptionInfo(at indexPath: IndexPath) -> StockSubscriptionInfo? {
let index = indexPath.row
if subscriptionList.indices.contains(index) {
return subscriptionList[index]
}
return nil
}
func requestStockSubscription() {
let year = getQueryYear()
subscriptionManager.requestStockSubscriptionInfo(year: year) { [weak self] subscriptionList, error in
// 需要去掉中央债的资料
self?.subscriptionList = self?.filterNotAvailable(subscriptionList) ?? []
self?.delegate?.didRecieveList(subscriptionList, error: error)
}
}
/// 命名可以用 rename 改得更符合变数意义,请自行变更
func getPricePercentDifferenctString(subscription: StockSubscriptionInfo) -> String? {
let code = subscription.stockCode
let subscriptionPrice = subscription.price
if let tick = getTick(from: code),
let subscriptionPriceDouble = numberFormatter.number(from: subscriptionPrice)?.doubleValue,
let closePrice = tick.close {
let percentage = (closePrice - subscriptionPriceDouble) / subscriptionPriceDouble
let string = String(format: "%.1f", percentage * 100)
return string
}
return nil
}
}
extension StockSubscriptionModel {
enum SubscriptionState {
case beforeSubscription
case duringSubscription
case finishedSubscription
case notDefined
}
}
extension StockSubscriptionModel {
func getSubscriptionState(info: StockSubscriptionInfo) -> SubscriptionState {
let currentTime = Date().timeIntervalSince1970
if let startTime = info.subscriptionStart?.timeIntervalSince1970,
let endTime = info.subscriptionEnd?.timeIntervalSince1970 {
if currentTime < startTime {
return .beforeSubscription
} else if currentTime > endTime {
return .finishedSubscription
} else {
return .duringSubscription
}
}
return .notDefined
}
}
台股申购日历
IT铁人赛Demo App
下方是这次 D1 ~ D12 的完成品,可以下载来试
App Store - 台股申购日历
>>: Day29 使用 addTransceiver 单向接收串流
我们看电视综艺节目的森川葵,不管学习什麽技艺,都能很快学会,让教的人相当惊讶,且啧啧称奇,把这个电视...
字典(dict) 今天要来跟大家介绍字典(dict), 字典储存的资料为「键(key)」与「值(va...
在 Fluentd Bit 中可以使用 read 或 socket 方式处理日志 read 用於读容...
前言: 到了要开始处理资料的部分,因为影像资料会有档案太大或是大小不一的问题,所以都要先预设成固定的...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2...