一旦我的ContentView加载了所有的网络数据,我想要执行快照函数。我对API调用没有问题,我只是想让快照函数在所有数据加载到ContentView之后运行。
按下按钮后的预期结果:按下按钮后的预期效果
按下按钮后的实际结果:按按钮后的实际效果
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 --运行API调用的ViewModel
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 发布于 2021-09-16 15:35:58
如果您遵循命名类型和变量的Swift API设计指南,一般会得到更多更好的帮助。这意味着对属性和方法的初始字母使用小写,对类型的初始字母使用大写。据我所知,您可能来自一个像C#这样的平台,那里的约定是不同的。但是,如果您不以Swift的方式(或者更糟糕的是,在您的代码中,两者都做!)做的事情,您会使我们更难理解您的代码。
此外,这也是一个糟糕的模式:
@ObservedObject var FetchResults = fetchResults()
问题是SwiftUI不理解FetchResults对象的所有权,每次重新创建视图时都会重新创建它。在这种情况下,您应该使用@StateObject:
@StateObject var fetchResults = FetchResults()查看保罗·哈德森撰写的这篇文章,了解何时使用@StateObject和何时使用@ObservableObject的指导。
然而,这并不能解决你发布的问题。代码通过这样的方式创建快照:contentView.Snapshot(),它调用您的contentView计算属性,它从头创建一个新的ContentView,它创建一个新的、卸载的FetchResults (不管您是使用@ObservedObject还是@StateObject)。
您需要重用已经加载其数据的FetchResults,因此只需使用self.snapshot():
Button(
action: {
let image = self.snapshot()
print(image)
},
label: {
Text("press me to print view")
}
)https://stackoverflow.com/questions/69209596
复制相似问题