Post

Replies

Boosts

Views

Activity

Why do I get a "Publishing changes from within view updates is not allowed" when moving my @Bindings to @Published in an @ObservableObject?
Am going through a SwiftUI course, so the code is not my own. When I migrated my @Bindings into @Published items in an @ObservableObject I started getting the following error: Publishing changes from within view updates is not allowed, this will cause undefined behavior. The warning occurs in the ScannerView which is integrated with the main view, BarcodeScannerView. It occurs when an error occurs, and scannerView.alertItem is set to a value. However, it does not occur when I am setting the value of scannerView.scannedCode, and as far as I can tell, they both come from the sample place, and are the same actions. There are tons of posts like mine, but I have yet to find an answer. Any thoughts or comments would be very appreciated. BarcodeScannerView import SwiftUI struct BarcodeScannerView: View { @StateObject var viewModel = BarcodeScannerViewModel() var body: some View { NavigationStack { VStack { ScannerView(scannedCode: $viewModel.scannedCode, typeScanned: $viewModel.typeScanned, alertItem: $viewModel.alertItem) .frame(maxWidth: .infinity, maxHeight: 300) Spacer().frame(height: 60) BarcodeView(statusText: viewModel.typeScanned) TextView(statusText: viewModel.statusText, statusTextColor: viewModel.statusTextColor) } .navigationTitle("Barcode Scanner") .alert(item: $viewModel.alertItem) { alertItem in Alert(title: Text(alertItem.title), message: Text(alertItem.message), dismissButton: alertItem.dismissButton) } } } } BarcodeScannerViewModel import SwiftUI final class BarcodeScannerViewModel: ObservableObject { @Published var scannedCode = "" @Published var typeScanned = "Scanned Barcode" @Published var alertItem: AlertItem? var statusText: String { return scannedCode.isEmpty ? "Not Yet scanned" : scannedCode } var statusTextColor: Color { scannedCode.isEmpty ? .red : .green } } ScannerView import SwiftUI struct ScannerView: UIViewControllerRepresentable { typealias UIViewControllerType = ScannerVC @Binding var scannedCode : String @Binding var typeScanned : String @Binding var alertItem: AlertItem? func makeCoordinator() -> Coordinator { Coordinator(scannerView: self) } func makeUIViewController(context: Context) -> ScannerVC { ScannerVC(scannerDelegate: context.coordinator) } func updateUIViewController(_ uiViewController: ScannerVC, context: Context) { } final class Coordinator: NSObject, ScannerVCDelegate { private let scannerView: ScannerView init(scannerView: ScannerView) { self.scannerView = scannerView } func didFind(barcode: String, typeScanned: String) { scannerView.scannedCode = barcode scannerView.typeScanned = typeScanned print (barcode) } func didSurface(error: CameraError) { switch error { case .invalidDeviceinput: scannerView.alertItem = AlertContext.invalidDeviceInput case .invalidScannedValue: scannerView.alertItem = AlertContext.invalidScannedValue case .invalidPreviewLayer: scannerView.alertItem = AlertContext.invalidPreviewLayer case .invalidStringObject: scannerView.alertItem = AlertContext.invalidStringObject } } } }
4
0
5.1k
Mar ’23
Why must I wrap a call to call to an async/await method in a Task?
Trying to to convert my old URL functionality to SwiftUI with async/await. While the skeleton below works, am puzzled as to why I must place my call to the method within a Task? When I don't use Task I get the error: Cannot pass function of type '() async -> Void' to parameter expecting synchronous function type From the examples I've seen, this wasn't necessary. So I either I've misunderstood something, or I am doing this incorrectly, and am looking for little but of guidance. Thank you Within my SwiftUI view: Button { Task { let request = xFile.makePostRequest(xUser: xUser, script: "requestTicket.pl") var result = await myNewURL.asyncCall(request: request) print("\(result)") } } From a separate class: class MyNewURL: NSObject, ObservableObject { func asyncCall(request: URLRequest) async -> Int { do { let (data, response) = try await URLSession.shared.data(for: request) guard let httpResponse = response as? HTTPURLResponse else { print("error") return -1 } if httpResponse.statusCode == 200 { ... } } catch { return -2 } return 0 } }
1
0
3.6k
Jul ’23
Is there an .onAppear equivalent that works on individual items in a view, and also gets called on redraws?
Within my SwiftUI view I have multiple view items, buttons, text, etc. Within the view, the user selects a ticket, and then clicks a button to upload it. The app then sends the ticket to my server, where the server takes time to import the ticket. So my SwiftUI app needs to make repeated URL calls depending on how far the server has gotten with the ticket. I thought the code below would work. I update the text to show at what percent the server is at. However, it only works once. I guess I thought that onAppear would work with every refresh since it's in a switch statement. If I'm reading my debugger correctly, SwiftUI recalls which switch statement was called last and therefore it views my code below as a refresh rather than a fresh creation. So is there a modifier that would get fired repeatedly on every view refresh? Or do I have to do all my multiple URL calls from outside the SwiftUI view? Something like onInitialize but for child views (buttons, text, etc.) within the main view? switch myNewURL.stage { case .makeTicket: Text(myNewURL.statusMsg) .padding(.all, 30) case .importing: Text(myNewURL.statusMsg) .onAppear{ Task { try! await Task.sleep(nanoseconds: 7000000000) print ("stage two") let request = xFile.makeGetReq(xUser: xUser, script: "getTicketStat.pl") var result = await myNewURL.asyncCall(request: request, xFile: xFile) } } .padding(.all, 30) case .uploadOriginal: Text(myNewURL.statusMsg) .padding(.all, 30) case .JSONerr: Text(myNewURL.statusMsg) .padding(.all, 30) }
1
0
1.1k
Jul ’23
Can a button call a new view without using NavigationStack/Link/View?
Is it possible to switch to a new View without using NavigationStack or NavigationLink or NavigationView? I know I can do it with a Bool, which either shows the second view, or the first, and then toggles the Bool. But can't I do something like this? Which obviously doesn't work. struct BasicButton: View { var buttonLabel = "Create User" var body: some View { Button { CreateUser() //another SwiftUI view, not a function } label: { Text(buttonLabel) } } }
3
0
932
May ’24
Why doesn't Xcode's "Download Container" not always work?
Been using Xcode's Download Container for a short time, and at first there were no issues. But lately, it doesn't always download all the files from my iPhone to the Mac. Sometimes cleaning the build folder works, other times not. As well, the same happens whether I am connected to my iPhone via cable, or wifi. Has anyone else had this issue?
6
0
417
Nov ’24
Is there a global Alert View in SwiftUI?
I am writing a SwiftUI based app, and errors can occur anywhere. I've got a function that logs the error. But it would be nice to be able to call an Alert Msg, no matter where I am, then gracefully exits the app. Sure I can right the alert into every view, but that seems ridiculously unnecessary. Am I missing something?
2
0
130
Apr ’25
Is there a simple way to make a background fit the entire screen?
I have an SKScene, where I use an SKSpriteNode as the background. While the work I do below to make it fit to scale isn't much, I wondered if Swift provided a method or property that would do the same? From my GameScene override func didMove(to view: SKView){ super.didMove(to: view) self.backgroundColor = .clear let ratio = self.size.height / background.size.height background.size.height *= ratio background.size.width *= ratio background.anchorPoint = CGPoint(x: 0.0, y: 0.0) background.zPosition = -1 addChild(background) physicsWorld.contactDelegate = self self.isHidden = true From my main ViewController, where I create the GameScene let scene = WheelScene(size: myView.frame.size) scene.anchorPoint = CGPoint(x: 0.0, y: 0.0) scene.backgroundColor = .clear scene.scaleMode = .aspectFit wheelScene = scene mainView = myView myView.presentScene(wheelScene)
2
0
607
Mar ’21
Can I create an .fsh file from an image?
I wanted to use a png image to create a pattern for an SKSpriteNode. Supposedly: Pattern images are not supported via UIColor in SpriteKit So I am supposed to use an .fsh file for shading. The thing is, can I create such a file from an image? Everywhere I've looked only show's mathematical methods for creating those files. I hope this is something that is possible
0
0
651
Mar ’21
Need help on SQLite wrapper for Swift
I am using the SQLite wrapper for Xcode. I got it from the link below and did install it. But was hoping there would better documentation, or tutorials out there for it. Am new enough at Swift and its syntax. Whatever can make this easier for me would be a big help. https: //git.pado.name/reviewspur/ios/tree/fd2486cf91e422e2df8d048ffd2d40ea89527685/Carthage/Checkouts/SQLite.swift/Documentation#building-type-safe-sql
0
0
402
May ’21
What is the syntax for "if not" in Swift?
I have the code below which works just fine. getTwinklingGem returns type MyGem. What I cannot figure out is if there is a proper syntax for writing the NOT into the if statement. Am still too new to Swift. This works, but seems lengthy: if let twinkling = getHighGem(), twinkling != nil Is this the proper way to test for a nil return? if let twinkling = getHighGem() as? MyGem if let twinkling = getTwinklingGem() { print ("not nil") }
4
0
2.4k
Jun ’21
How to refine the shape of an SKSpriteNode for tap gestures?
In my app I create mutiple SKSpriteNodes, gems. Code snippet 1 When I loop through nodes from the main scene in a tap gesture, Code snippet 2, the gems register in a perfect square shape even though they are not. I have highlighted all areas that the orange gem registers in a tap as white. Here is the screen shot http://98.7.37.117/gem.png Since the gem is itself not a square, I'd like to know if there is a way refine its shape so it would only show up in the list of nodes in UITapGestureRecognizer if the orange part is tapped. I have even tried by assigning it a physicsBody. But that made no difference. Code Snippet 1 class MyGem : SKSpriteNode{ init(iColor : Gems) { fileName = "\(iColor)_gem" let skTexture = SKTexture(imageNamed: fileName) super.init(texture: skTexture, color: .clear, size: .zero) self.isHidden = true self.anchorPoint = CGPoint(x: 0.5, y: 0.5) self.size = CGSize(width: myGV.gemSize.width, height: myGV.gemSize.height) self.zPosition = theZ.gem self.position = CGPoint(x: 0, y: 0 ) self.isUserInteractionEnabled = false self.name = "gem" } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } Code Snippet 2 @objc func tappedView(_ sender:UITapGestureRecognizer) { if sender.state == .ended{ var post = sender.location(in: sender.view) post = self.convertPoint(fromView: post) for node in self.nodes(at: post){ if let touchNode = node as? MyGem print("touched gem") highliteGem(theGem: touchNode, clearAll: false) return }
6
0
919
Jul ’21