我 试图 弄 清楚 如何 从 Json 数据 ( 由 Financial Modeling Prep 提供 ) 创建 Core Data 对象 。
应用 程序 的 结构 如下 :
- 具有 如下 函数 的 API _ SERVICE 类 :
func readJsonIncomeStatementFMP(keywords: String) -> AnyPublisher<[IncomeStatementFMP], Error> {
let result = parseQuery(text: keywords)
var symbol = String()
switch result {
case .success(let query):
symbol = query
case .failure(let error):
return Fail(error: error).eraseToAnyPublisher()
}
let urlString = "https://financialmodelingprep.com/api/v3/income-statement/\(symbol)?apikey=\(API_KEY)"
let urlResult = parseURL(urlString: urlString)
switch urlResult {
case .success(let url):
return URLSession.shared.dataTaskPublisher(for: url)
.map({$0.data})
.decode(type: [IncomeStatementFMP].self, decoder: JSONDecoder())
.receive(on: RunLoop.main)
.eraseToAnyPublisher()
case .failure(let error):
return Fail(error: error).eraseToAnyPublisher()
}
}
中 的 每 一 个
- 调用 API _ SERVICE 的 SCREENER 视图 :
var body: some View {
@Environment(\.managedObjectContext) private var viewContext
//CoreData
@FetchRequest(entity: Entreprise.entity(), sortDescriptors: [NSSortDescriptor(key: "companyName", ascending: true)]) var entreprises: FetchedResults<Entreprise>
@State var subscribers = Set<AnyCancellable>()
@ObservedObject var apiServiceFMP = APIServiceFMP()
@State var resultScreener: [ResultScreener]?
@State var incomeStatementFMP: [IncomeStatementFMP]?
ZStack{
VStack{
ScrollView(.horizontal){
VStack{
Button(action: {
handleSelectionStockScreenerMultipleProperties(exchange: exchange, country: country, marketCap: marketCap)
}){
Text("Lancer le screen")
.fontWeight(.semibold)
}
.padding()
.foregroundColor(.white)
.background(Color(.green))
.cornerRadius(10)
}
if resultScreener != nil{
VStack{
List(searchResults, id: \.id){ results in
HStack{
Text(results.symbol)
Divider()
Text(results.companyName)
Divider()
Button(action: {
Task{
await handleSelectionIncomeStatementForFMP(for: results.symbol)
await handleSelectionBalanceSheetForFMP(for: results.symbol)
await handleSelectionCashFlowForFMP(for: results.symbol)
await handleSelectionCompanyOutlookForFMP(for: results.symbol)
await handleSelectionHistoricalDailyPriceFMP(for: results.symbol)
}
}){
Text("Infos").foregroundColor(.white)
}.buttonStyle(.plain)
if incomeStatementFMP != nil && balanceSheetFMP != nil && cashFlowFMP != nil && companyOutlookFMP != nil && historicalDailyPriceFMP != nil && incomeStatementFMP!.count > 0 {
if incomeStatementFMP![0].symbol == results.symbol{
Button(action: {
Task{
await handleSelectionIncomeStatementForFMP(for: results.symbol)
await handleSelectionBalanceSheetForFMP(for: results.symbol)
await handleSelectionCashFlowForFMP(for: results.symbol)
await handleSelectionCompanyOutlookForFMP(for: results.symbol)
await handleSelectionHistoricalDailyPriceFMP(for: results.symbol)
}
addEntreprise(incomeStatementFMP: incomeStatementFMP!, balanceSheetFMP: balanceSheetFMP!, cashFlowFMP: cashFlowFMP!, companyOutlookFMP: companyOutlookFMP!, ticker: results.symbol)
}){
Text("Ajout BDD").foregroundColor(.white)
}.buttonStyle(.plain)
.padding()
.background(.blue)
}
}
}
}
}
}
}
}
private func handleSelectionIncomeStatementForFMP(for symbol: String) async{
apiServiceFMP.readJsonIncomeStatementFMP(keywords: symbol).sink { (completionResult) in
switch completionResult {
case .failure(let error):
print(error)
case .finished: break
}
} receiveValue: { (incomeStatementResults) in
self.incomeStatementFMP = incomeStatementResults
}.store(in: &subscribers)
}
private func addEntreprise(incomeStatementFMP: [IncomeStatementFMP], balanceSheetFMP: [BalanceSheetFMP], cashFlowFMP: [CashFlowFMP], companyOutlookFMP: [CompanyOutlookFMP], ticker: String){
if incomeStatementFMP.count > 0 && balanceSheetFMP.count > 0 && cashFlowFMP.count > 0 {
if companyOutlookFMP[0].profile.symbol == ticker && incomeStatementFMP.count > 0 && incomeStatementFMP[0].symbol == ticker && balanceSheetFMP[0].symbol == ticker && cashFlowFMP[0].symbol == ticker{
if entreprises.filter({$0.ticker == ticker}).count != 0 {
for entreprise in entreprises.filter({$0.ticker == ticker}){
if entreprise.incomes!.count == incomeStatementFMP.count {
///Si les données fondamentales n'ont pas changé, on arrête
return
}
else {
///Si les données fondamentales sont plus nombreuses que celles déjà enregistrées
///Il mettre à jour les données de l'objet existant
print("Il faut intégrer la méthode pour modifier l'objet sans le recréer")
}
}
} else {
createNewEntreprise(companyOutlookFMP: companyOutlookFMP, incomeStatementFMP: incomeStatementFMP, balanceSheetFMP: balanceSheetFMP, cashFlowFMP: cashFlowFMP, historicalDailyPriceFMP: historicalDailyPriceFMP!, ticker: ticker)
}
}
} else {
print("Il n'y a pas assez de données, pas d'intérêt d'enregistrer l'entreprise")
}
}
func createNewEntreprise(companyOutlookFMP: [CompanyOutlookFMP], incomeStatementFMP: [IncomeStatementFMP], balanceSheetFMP: [BalanceSheetFMP], cashFlowFMP: [CashFlowFMP], historicalDailyPriceFMP: [HistoricalDailyPriceFMP], ticker: String){
if companyOutlookFMP[0].profile.symbol == ticker && incomeStatementFMP[0].symbol == ticker && balanceSheetFMP[0].symbol == ticker && cashFlowFMP[0].symbol == ticker && historicalDailyPriceFMP[0].symbol == ticker{
let newEntreprise = Entreprise(context: viewContext)
newEntreprise.ticker = companyOutlookFMP[0].profile.symbol
newEntreprise.industry = companyOutlookFMP[0].profile.industry
newEntreprise.sector = companyOutlookFMP[0].profile.sector
newEntreprise.companyName = companyOutlookFMP[0].profile.companyName
newEntreprise.currency = companyOutlookFMP[0].profile.currency
newEntreprise.region = companyOutlookFMP[0].profile.country
newEntreprise.exchange = companyOutlookFMP[0].profile.exchangeShortName
let s = companyOutlookFMP[0].profile.isin
let any : Any? = s
if any != nil {
newEntreprise.isin = companyOutlookFMP[0].profile.isin
} else {
newEntreprise.isin = "Pas de ISIN"
}
newEntreprise.lastPrice = Array(getLastDailyPrice(historicalDailyPrice: historicalDailyPriceFMP)).sorted(by: >)[0].value
newEntreprise.dateLastPrice = Array(getLastDailyPrice(historicalDailyPrice: historicalDailyPriceFMP)).sorted(by: >)[0].key
//Ajouter les données fondamentales
for i in addIncomeToEnterprise(incomeStatementFMP: incomeStatementFMP){
newEntreprise.addToIncomes(i)
//On enregistre les Income Statement
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
for i in addBalanceToEnterprise(balanceSheetFMP: balanceSheetFMP){
newEntreprise.addToBalances(i)
//On enregistre les Balance Sheet
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
for i in addCashToEnterprise(cashFlowFMP: cashFlowFMP){
newEntreprise.addToCashFlows(i)
//On enregistre les Cash Flow
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
//On enregistre l'objet newEntreprise avec toutes les Relationships
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
}
格式
我 认为 我们 应该 使用 异步 等待 的 概念 。
我 想 加载 的 数据 与 一 个 点击 " Ajout BDD " 。
这 就是 它 不能 完美 工作 的 地方 - 〉 我 必须 先 单击 * * " Info " * * 按钮 , 它 调用 API _ SERVICE 函数 , 然后 才 能 按 下 * * " Ajout BDD " * * 按钮 , 它 用于 创建 核心 对象 数据 。
为什么 当 我 直接 按 * * " Ajout BDD " * * 时 没有 任何 React ? 如果 我 按 两 次 , 它 会 将 对象 添加 到 Core Data 中 。
谢谢 你 的 帮助
1条答案
按热度按时间vptzau2j1#
我 发现 了 一 个 需要 改进 的 解决 方案 , 但 它 很 有效 。 在 我 想 监控 的 四 个 变量 中 , 我 添加 了 一 个 DidSet :
中 的 每 一 个
其余 部分 由 函数 observeEntreprise 处理 :
格式