数据加载到视图SwiftUI后执行功能
Posted
技术标签:
【中文标题】数据加载到视图SwiftUI后执行功能【英文标题】:Executing function after data loads into view SwiftUI 【发布时间】:2021-09-16 13:45:23 【问题描述】:我希望在我的 ContentView 加载所有网络数据后执行快照功能。我对 API 调用没有任何问题,我只是希望 Snapshot 函数在所有数据加载到 ContentView 后运行。
按下按钮后的预期结果: Expected result after pressing button
按下按钮后的实际结果: Actual result after pressing button
ContentView.swift
extension View
func Snapshot() -> UIImage
let controller = UIHostingController(rootView: self)
let view = controller.view
let targetSize = controller.view.intrinsicContentSize
view?.bounds = CGRect(origin: .zero, size: targetSize)
view?.backgroundColor = .clear
let renderer = UIGraphicsImageRenderer(size: targetSize)
return renderer.image _ in
view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
struct ContentView: View
@ObservedObject var FetchResults = fetchResults()
var contentView: some View
ContentView()
var body: some View
Group
if FetchResults.dataHasLoaded
VStack
Text(FetchResults.clout.postFound?.body ?? "n/a")
.padding()
.background(Color.blue)
.mask(RoundedRectangle(cornerRadius: 30, style: .continuous))
.shadow(color: Color(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)).opacity(0.3), radius: 10, x: 0, y:10)
.padding()
.frame(maxWidth: 300)
Button(action:
let image = contentView.Snapshot()
print(image)
, label:Text("press me to print view"))
else
Text("loading data")
GotPost.swift -- 我的 ViewModel 运行 API 调用
class fetchResults: ObservableObject
@Published var clout = Cloutington()
@Published var dataHasLoaded = false
init()
getData clout in
self.clout = clout
private func getData(completion: @escaping (Cloutington) -> ())
let parameters = "\r\n \"PostHashHex\": \"2f9633c2460f23d9d5690fe9fd058457ebeb01f6f75805aa426cdaab90a1f4b4\"\r\n"
let postData = parameters.data(using: .utf8)
var request = URLRequest(url: URL(string: "https://bitclout.com/api/v0/get-single-post")!,timeoutInterval: Double.infinity)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = postData
request.httpMethod = "POST"
let task = URLSession.shared.dataTask(with: request) (responseData, response, error) in
print(error)
print(response)
print(responseData)
if let resData = responseData
let decoder = JSONDecoder()
do
let finalData = try decoder.decode(Cloutington.self, from: resData)
DispatchQueue.main.async
completion(finalData)
self.dataHasLoaded = true
catch (let error)
print(error)
task.resume()
PostFound.swift -- 模型解析 JSON 数据
struct Cloutington: Decodable
var postFound: PostFound?
enum CodingKeys: String, CodingKey
case postFound = "PostFound"
struct PostFound: Decodable
var id: String?
var postHashHex, posterPublicKeyBase58Check, parentStakeID, body: String?
var imageURLs: [String]?
// var recloutedPostEntryResponse: JSONNull?
var creatorBasisPoints, stakeMultipleBasisPoints: Int?
var timestampNanos: Double?
var isHidden: Bool?
var confirmationBlockHeight: Int?
var inMempool: Bool?
var profileEntryResponse: ProfileEntryResponse?
var likeCount, diamondCount: Int?
var isPinned: Bool?
var commentCount, recloutCount: Int?
var diamondsFromSender: Int?
enum CodingKeys: String, CodingKey
case postHashHex = "PostHashHex"
case posterPublicKeyBase58Check = "PosterPublicKeyBase58Check"
case parentStakeID = "ParentStakeID"
case body = "Body"
case imageURLs = "ImageURLs"
case creatorBasisPoints = "CreatorBasisPoints"
case stakeMultipleBasisPoints = "StakeMultipleBasisPoints"
case timestampNanos = "TimestampNanos"
case isHidden = "IsHidden"
case confirmationBlockHeight = "ConfirmationBlockHeight"
case inMempool = "InMempool"
case profileEntryResponse = "ProfileEntryResponse"
case likeCount = "LikeCount"
case diamondCount = "DiamondCount"
case isPinned = "IsPinned"
case commentCount = "CommentCount"
case recloutCount = "RecloutCount"
case diamondsFromSender = "DiamondsFromSender"
// MARK: - ProfileEntryResponse
struct ProfileEntryResponse: Decodable
var publicKeyBase58Check, username, profileEntryResponseDescription, profilePic: String?
var isHidden, isReserved, isVerified: Bool?
var coinPriceBitCloutNanos, stakeMultipleBasisPoints: Int?
enum CodingKeys: String, CodingKey
case publicKeyBase58Check = "PublicKeyBase58Check"
case username = "Username"
case profileEntryResponseDescription = "Description"
case profilePic = "ProfilePic"
case isHidden = "IsHidden"
case isReserved = "IsReserved"
case isVerified = "IsVerified"
case coinPriceBitCloutNanos = "CoinPriceBitCloutNanos"
case stakeMultipleBasisPoints = "StakeMultipleBasisPoints"
```
Really appreciate the help ????
【问题讨论】:
这是一个计算属性,因此您可能会重新创建内容视图而不是实际拍摄屏幕快照。试试self.Snapshot()
@DeveloperDank 如果你使用 self.Snapshot(),它也会在快照中包含“按我打印视图”。
【参考方案1】:
如果您遵循Swift API Design Guidelines 来命名类型和变量,您通常会获得更多更好的帮助。这意味着对属性和方法的首字母使用小写,对类型的首字母使用大写。我了解您可能来自 C# 等约定不同的平台。但是当你不以 Swift 的方式做事时(或者更糟糕的是,在你的代码中,你两者都做!),你会让我们更难理解你的代码。
另外,这是一个糟糕的模式:
@ObservedObject var FetchResults = fetchResults()
问题在于 SwiftUI 不理解 FetchResults
对象的所有权,并且每次重新创建视图时都会重新创建它。在这种情况下,您应该改用@StateObject
:
@StateObject var fetchResults = FetchResults()
查看this article by Paul Hudson,了解何时使用@StateObject
以及何时使用@ObservableObject
。
但是,这并不能解决您发布的问题。您的代码通过说contentView.Snapshot()
创建快照,它调用您的contentView
计算属性,它从头开始创建一个新的ContentView
,它创建一个新的、未加载的FetchResults
(无论您使用的是@ObservedObject
还是@ 987654334@).
你需要重用已经加载了数据的FetchResults
,所以直接说self.snapshot()
吧:
Button(
action:
let image = self.snapshot()
print(image)
,
label:
Text("press me to print view")
)
【讨论】:
抢你的传奇!谢谢你,非常感谢你的建议?以上是关于数据加载到视图SwiftUI后执行功能的主要内容,如果未能解决你的问题,请参考以下文章
为啥核心数据不会在 swiftui 类中加载,但会在结构视图中加载
LinkPresentation 视图未在 SwiftUI 中完全加载
合并SwiftUI远程获取数据-ObjectBinding不会更新视图