In my app the object collecting errors and alerts (also from an external device) is a global singleton and cannot live only in the UI. Also this is very likely a problem with the UiKit viewcontroller that provides the Alert and its transition. The reference to the observed object is never lost - otherwise it wouldn't work with the delay. The real problem from my perspective is that the transition of the Alert that is not finished.
Post
Replies
Boosts
Views
Activity
In addition - this behavior is quite nasty if the alert is presented ontop of a sheet or popover. If the sheet is dismissed before the alert has completed its transition the sheet is stuck.
And here ist the Output I ge when the delay is remove...
You could actually argue that .alert is not respecting SwiftUIs core principles of "One Truth" ;-)
Next Message One
Getting new state: true
Getting new state: false
Next Message Two
Getting new state: true
Getting new state: false
Next Message Three
2022-12-05 09:15:21.280381+0100 Dummy[15473:8198016] [Presentation] Attempt to present <SwiftUI.PlatformAlertController: 0x13f052000> on <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x159814a00> (from <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x159814a00>) which is already presenting <SwiftUI.PlatformAlertController: 0x158037800>.
Getting new state: true
Getting new state: false
Next Message Four
2022-12-05 09:15:24.429913+0100 Dummy[15473:8198016] [Presentation] Attempt to present <SwiftUI.PlatformAlertController: 0x13f052000> on <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x159814a00> (from <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x159814a00>) which is already presenting <SwiftUI.PlatformAlertController: 0x158037800>.
Getting new state: true
Getting new state: false
Next Message Five
2022-12-05 09:15:27.584491+0100 Dummy[15473:8198016] [Presentation] Attempt to present <SwiftUI.PlatformAlertController: 0x13f052000> on <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x159814a00> (from <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x159814a00>) which is already presenting <SwiftUI.PlatformAlertController: 0x158037800>.
Getting new state: true
Getting new state: false
Here is a little example of what I mean. If you take out the delay - it stops working:
import Combine
class Messages : ObservableObject {
static var shared = Messages()
@Published var isPresented:Bool = false
@Published var message:String = ""
var messages = ["One", "Two", "Three", "Four", "Five" ]
var subscriptions:[AnyCancellable] = []
init() {
$isPresented
.delay(for: .seconds(1), scheduler: DispatchQueue.main) // <- Take out this delay and it stops working.
.receive(on: DispatchQueue.main)
.sink{ [weak self] state in
print ("Getting new state: \(state)")
if state == false {
self?.next()
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { [weak self] in
if self?.isPresented == true {
self?.isPresented = false
}
}
}
}
.store(in: &subscriptions)
}
func next() {
if messages.isEmpty == false {
self.message = messages.removeFirst()
self.isPresented = true
print ("Next Message \(self.message)")
}
}
}
@main
struct DummyApp: App {
@ObservedObject var messages = Messages.shared
@State var isPresented = false
var body: some Scene {
WindowGroup {
VStack {
Button("isPresented: \(String(describing:messages.isPresented))"){
messages.isPresented = true
}
.frame(width:150, height:100)
.alert("My Alert", isPresented: $isPresented, actions: { Button("OK"){} }, message:{ Text(messages.message) } )
.onReceive(messages.$isPresented){ state in
isPresented = state
}
Color.clear
.frame(width: 100,height: 300)
}
}
}
}
Never mind - Seems like I resolved the issue. Looks like it is a bad idea to put a LazyVGrid into a List View.
I removed the surrounding List View and now it seems fine. Somehow strange that it did work before Ventura.
Forgot the error description...
*** Assertion failure in -[UICollectionViewData indexPathForItemAtGlobalIndex:], UICollectionViewData.mm:835
2022-11-22 15:03:07.448874+0100 CameraCompanionBETA[3997:41963] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'request for index path for global index 4 when there are only 4 items in the collection view'
Ha! I figured it out...
When the App has the "Mobile Data" setting turned off in Settings, then I need to disable Mobile Data for the App to connect to the local Wifi.
If I turn mobile data on though - everything works as expected.
This sounds a bit like a bug in iOS to me, tbh.
Cheers!
Never mind... problem resolved. This was a combination of a couple unlikely events in combination... (Is there a way to delete this question? :-) )
Hi Matt,
previously I had another layer using WatchCommunication in-between the watch and the iPhone - which was cumbersome and complicated. Now I migrated to using my protocol adapter (which is using network.framework and Combine) directly on the watch which not only enhanced performance but also drastically reduced the code size and increased development speed.
It seems since I disconnect when I background the app (the network protocol is binary and super low overhead and reconnect is quick) everything works amazingly well. The only problem I had was cached endpoints, which apparently don't seem to work. My only problem is that I cannot get rid of the phone in the network, which would be a huge benefit. The way it is you always need to have the phone close by and connected to the Wifi of the camera.
Everybody is actually quite blown away by the iWatch becoming a low profile interface - it turns into an indispensable professional tool which a lot of my customers don't want to miss...
But I recon the 'prefer companion' option on the nwconnection is fixed in iWatch - at least I did not find it anywhere in the header files.
michael
Addition:
When I disable Wifi on the phone the debug output I get on the nwconnection is:
Connection Waiting! Optional([C6 192.168.153.1:5055 tcp, indefinite, no cellular, prefer companion, path unsatisfied (Path was denied by NECP policy), interface: ipsec1, ipv4, ipv6]) error:POSIXErrorCode: Network is down
I haven't seen the "prefer companion" part before - I guess this is my problem. Is there any configuration option for this part on the connection? Apart from this everything works as expected.