SwiftUI 使用计时器每 60 秒发布 API 数据
SwiftUI publishing API data every 60 seconds with a Timer
我这几天一直在追自己的尾巴。。可能是架构全错了。我只是不能让所有的东西同时工作。任何帮助将不胜感激。
我有一个 LoginView
,它接受电子邮件和密码,并向服务器验证。
import SwiftUI
struct LoginView: View {
@EnvironmentObject var userAuth: UserAuth
@State private var email: String = ""
@State private var password: String = ""
var body: some View {
TextField("Email Address", text: $email)
SecureField("Password", text: $password)
Button(action: {
guard let url = URL(string: "https://www.SomeLoginApi.com/login") else { return }
let body: [String: String] = ["emailAddress": email, "password": password]
let finalBody = try! JSONSerialization.data(withJSONObject: body)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = finalBody
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request) { (data, _, _) in
guard let data = data else { return }
let loginResponse = try! JSONDecoder().decode(ServerResponse.self, from: data)
if loginResponse.message == "authorized" {
DispatchQueue.main.async {
self.userAuth.isLoggedIn = true
self.userAuth.userId = loginResponse.userId
AppData().getData(userId: userAuth.userId)
}
} else {
var isLoggedin = false
}
}
.resume()
}) {
Text("LOGIN")
}
.disabled(email.isEmpty || password.isEmpty)
}
如果经过验证,上面的代码将执行以下操作:
- 将
isLoggedIn
设置为 true
,通过以下 StartingView
: 将视图更改为 MainView
import SwiftUI
struct StartingView: View {
@EnvironmentObject var userAuth: UserAuth
var body: some View {
if !userAuth.isLoggedIn {
LoginView()
} else {
MainView()
}
}
}
- 向服务器发送第二次 API 调用
AppData().getData(userId: userAuth.userId)
以获取数据。
这里是上面的API指向的AppData
class
import Foundation
import SwiftUI
import Combine
import CoreImage
import CoreImage.CIFilterBuiltins
class AppData : ObservableObject {
@Published var userData: AppDataModel = AppDataModel(data1: "", data2: "", data3: "", data4: "", data5: "", data6: "", data7: "", bool1: false, data8: "", data9: "", bool2: true, bool3: true, bool4: true, bool5: true, bool6: true, data10: "", data11: "", data12: "", data13: "", array1:[], array2: [], array3: [], array4: [], array5: [], array6: [])
@Published var time = ""
@Published var greet = ""
@Published var bgImage = Image.init("")
init() {
var greetingTimer: Timer?
greetingTimer = Timer.scheduledTimer(timeInterval: 60.0, target: self, selector: #selector(getData), userInfo: nil, repeats: true)
}
@objc func getData(userId: String) {
let bgImgArr = ["appBackAnimals1", "appBackAnimals2", "appBackAnimals3", "appBackAnimals4", "appBackAnimals5", "appBackAnimals6", "appBackAnimals7", "appBackAnimals8", "appBackAnimals9", "appBackAnimals10", "appBackAnimals11", "appBackAnimals12", "appBackAnimals13"]
let bgImg = bgImgArr.randomElement()!
guard let inputImage = UIImage(named: bgImg) else { return }
let beginImage = CIImage(image: inputImage)
let context = CIContext()
let currentFilter = CIFilter.vignette()
currentFilter.inputImage = beginImage
currentFilter.intensity = 6
// get a CIImage from our filter or exit if that fails
guard let outputImage = currentFilter.outputImage else { return }
// attempt to get a CGImage from our CIImage
if let cgimg = context.createCGImage(outputImage, from: outputImage.extent) {
// convert that to a UIImage
let uiImage = UIImage(cgImage: cgimg)
// and convert that to a SwiftUI image
self.bgImage = Image(uiImage: uiImage)
}
let today = Date()
let formatter = DateFormatter()
formatter.dateFormat = "EEEE h:mma"
formatter.amSymbol = "am"
formatter.pmSymbol = "pm"
let calendar = Calendar.current
let hour = calendar.component(.hour, from: today)
time = formatter.string(from: today)
if hour >= 5 && hour <= 11 {
greet = "morning"
} else if hour >= 12 && hour <= 17 {
greet = "afternoon"
} else if hour >= 18 && hour <= 20 {
greet = "evening"
} else if hour >= 21 && hour <= 24 {
greet = "night"
} else if hour >= 0 && hour <= 4 {
greet = "night"
}
guard let url = URL(string: "https://www.SomeDataApi.com/data") else { return }
let body: [String: String] = ["userId": userId]
let finalBody = try! JSONSerialization.data(withJSONObject: body)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = finalBody
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request) { (data, _, _) in
guard let data = data else { return }
let apiData = try! JSONDecoder().decode(AppDataModel.self, from: data)
if apiData.message == "data" {
DispatchQueue.main.async {
self.userData = apiData
}
}
}
.resume()
if userData.appTopLine == "" {
userData.appTopLine = "Good " + greet + " " + userData.appName
} else {
userData.appTopLine = "not working"
}
if userData.appBottomLine == "" {
userData.appBottomLine = "It's " + time
}
}
}
这里是 MainView
我想显示数据的地方
import SwiftUI
struct MainView: View {
@ObservedObject var profileData = AppData()
@EnvironmentObject var userAuth: UserAuth
var body: some View {
ZStack {
profileData.bgImage
HStack {
VStack(alignment: .leading) {
Text(profileData.userData.appTopLine)
Text(profileData.userData.appBottomLine)
}
}
}
}
}
我遇到的问题:
我能够 print(apiData)
并查看数据,但是 @Published var userData
和 self.userData = apiData
无法通过 MainView
提供数据=27=]
getData()
不会用 Timer
每 60 秒触发一次,因为我不知道如何在其中传递 (userId: userAuth.userId)
参数。
我非常感谢任何指导。如果这不是 set-up 理想的方式,请告诉我,我想正确地做到这一点。
谢谢!
LoginView
中AppData().getData(userId: userAuth.userId)
的实例与@ObservedObject var profileData = AppData()
不同。
ObservedObject
永远看不到 LoginView
在做什么。
您必须像使用 UserAuth
或 singleton(不太推荐)那样使用 SwiftUI 包装器来共享实例。
class Singleton {
static let sharedInstance = Singleton()
}
另外,AppDataModel
是什么?是 ObservableObject
吗?你不能链接它们。
如果是,则这些变化 userData.appTopLine = "not working"
没有被观察到。你不会看到它们。
@Published var timeElapsed = false
func delayText() {
// Delay of 7.5 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 7.5) {
self.timeElapsed = true
}
}
那是一个定时器,希望对你有帮助。这对我有用,希望对你也有用。
我这几天一直在追自己的尾巴。。可能是架构全错了。我只是不能让所有的东西同时工作。任何帮助将不胜感激。
我有一个 LoginView
,它接受电子邮件和密码,并向服务器验证。
import SwiftUI
struct LoginView: View {
@EnvironmentObject var userAuth: UserAuth
@State private var email: String = ""
@State private var password: String = ""
var body: some View {
TextField("Email Address", text: $email)
SecureField("Password", text: $password)
Button(action: {
guard let url = URL(string: "https://www.SomeLoginApi.com/login") else { return }
let body: [String: String] = ["emailAddress": email, "password": password]
let finalBody = try! JSONSerialization.data(withJSONObject: body)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = finalBody
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request) { (data, _, _) in
guard let data = data else { return }
let loginResponse = try! JSONDecoder().decode(ServerResponse.self, from: data)
if loginResponse.message == "authorized" {
DispatchQueue.main.async {
self.userAuth.isLoggedIn = true
self.userAuth.userId = loginResponse.userId
AppData().getData(userId: userAuth.userId)
}
} else {
var isLoggedin = false
}
}
.resume()
}) {
Text("LOGIN")
}
.disabled(email.isEmpty || password.isEmpty)
}
如果经过验证,上面的代码将执行以下操作:
- 将
isLoggedIn
设置为true
,通过以下StartingView
: 将视图更改为
MainView
import SwiftUI
struct StartingView: View {
@EnvironmentObject var userAuth: UserAuth
var body: some View {
if !userAuth.isLoggedIn {
LoginView()
} else {
MainView()
}
}
}
- 向服务器发送第二次 API 调用
AppData().getData(userId: userAuth.userId)
以获取数据。
这里是上面的API指向的AppData
class
import Foundation
import SwiftUI
import Combine
import CoreImage
import CoreImage.CIFilterBuiltins
class AppData : ObservableObject {
@Published var userData: AppDataModel = AppDataModel(data1: "", data2: "", data3: "", data4: "", data5: "", data6: "", data7: "", bool1: false, data8: "", data9: "", bool2: true, bool3: true, bool4: true, bool5: true, bool6: true, data10: "", data11: "", data12: "", data13: "", array1:[], array2: [], array3: [], array4: [], array5: [], array6: [])
@Published var time = ""
@Published var greet = ""
@Published var bgImage = Image.init("")
init() {
var greetingTimer: Timer?
greetingTimer = Timer.scheduledTimer(timeInterval: 60.0, target: self, selector: #selector(getData), userInfo: nil, repeats: true)
}
@objc func getData(userId: String) {
let bgImgArr = ["appBackAnimals1", "appBackAnimals2", "appBackAnimals3", "appBackAnimals4", "appBackAnimals5", "appBackAnimals6", "appBackAnimals7", "appBackAnimals8", "appBackAnimals9", "appBackAnimals10", "appBackAnimals11", "appBackAnimals12", "appBackAnimals13"]
let bgImg = bgImgArr.randomElement()!
guard let inputImage = UIImage(named: bgImg) else { return }
let beginImage = CIImage(image: inputImage)
let context = CIContext()
let currentFilter = CIFilter.vignette()
currentFilter.inputImage = beginImage
currentFilter.intensity = 6
// get a CIImage from our filter or exit if that fails
guard let outputImage = currentFilter.outputImage else { return }
// attempt to get a CGImage from our CIImage
if let cgimg = context.createCGImage(outputImage, from: outputImage.extent) {
// convert that to a UIImage
let uiImage = UIImage(cgImage: cgimg)
// and convert that to a SwiftUI image
self.bgImage = Image(uiImage: uiImage)
}
let today = Date()
let formatter = DateFormatter()
formatter.dateFormat = "EEEE h:mma"
formatter.amSymbol = "am"
formatter.pmSymbol = "pm"
let calendar = Calendar.current
let hour = calendar.component(.hour, from: today)
time = formatter.string(from: today)
if hour >= 5 && hour <= 11 {
greet = "morning"
} else if hour >= 12 && hour <= 17 {
greet = "afternoon"
} else if hour >= 18 && hour <= 20 {
greet = "evening"
} else if hour >= 21 && hour <= 24 {
greet = "night"
} else if hour >= 0 && hour <= 4 {
greet = "night"
}
guard let url = URL(string: "https://www.SomeDataApi.com/data") else { return }
let body: [String: String] = ["userId": userId]
let finalBody = try! JSONSerialization.data(withJSONObject: body)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = finalBody
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request) { (data, _, _) in
guard let data = data else { return }
let apiData = try! JSONDecoder().decode(AppDataModel.self, from: data)
if apiData.message == "data" {
DispatchQueue.main.async {
self.userData = apiData
}
}
}
.resume()
if userData.appTopLine == "" {
userData.appTopLine = "Good " + greet + " " + userData.appName
} else {
userData.appTopLine = "not working"
}
if userData.appBottomLine == "" {
userData.appBottomLine = "It's " + time
}
}
}
这里是 MainView
我想显示数据的地方
import SwiftUI
struct MainView: View {
@ObservedObject var profileData = AppData()
@EnvironmentObject var userAuth: UserAuth
var body: some View {
ZStack {
profileData.bgImage
HStack {
VStack(alignment: .leading) {
Text(profileData.userData.appTopLine)
Text(profileData.userData.appBottomLine)
}
}
}
}
}
我遇到的问题:
我能够
print(apiData)
并查看数据,但是@Published var userData
和self.userData = apiData
无法通过MainView
提供数据=27=]getData()
不会用Timer
每 60 秒触发一次,因为我不知道如何在其中传递(userId: userAuth.userId)
参数。
我非常感谢任何指导。如果这不是 set-up 理想的方式,请告诉我,我想正确地做到这一点。
谢谢!
LoginView
中AppData().getData(userId: userAuth.userId)
的实例与@ObservedObject var profileData = AppData()
不同。
ObservedObject
永远看不到 LoginView
在做什么。
您必须像使用 UserAuth
或 singleton(不太推荐)那样使用 SwiftUI 包装器来共享实例。
class Singleton {
static let sharedInstance = Singleton()
}
另外,AppDataModel
是什么?是 ObservableObject
吗?你不能链接它们。
如果是,则这些变化 userData.appTopLine = "not working"
没有被观察到。你不会看到它们。
@Published var timeElapsed = false
func delayText() {
// Delay of 7.5 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 7.5) {
self.timeElapsed = true
}
}
那是一个定时器,希望对你有帮助。这对我有用,希望对你也有用。