Post

Replies

Boosts

Views

Activity

Implementing custom modifier with state logic
Inspired by the answer in this post I've been trying to implement the same idea with the addition of state handling inside the modifier. ViewModifier supports this, but the custom implementation does not trigger the state change. I wonder what would be missing from the custom implementation below to make it work with local state. An example: Here the tap is triggered, however, the view does not update. protocol TextModifier {   associatedtype Body: View   func body(text: Text) -> Body } extension Text {   func modifier<TM: TextModifier>(_ _modifier: TM) -> some View {     return _modifier.body(text: self)   } } struct HulkSmash: TextModifier {   @State var isHulk: Bool = false   func body(text: Text) -> some View {     text.bold()       .font(isHulk ? .system(.largeTitle, design: .rounded) : .body)       .foregroundColor(isHulk ? .init(.systemGreen) : .init(.systemFill))       .onTapGesture {         print("tap triggered")         isHulk.toggle()       }   } } struct ViewModifierTestView: View {   var body: some View {     Text("Test")       .modifier(HulkSmash())   } } Working example with ViewModifier: struct TapToTitle: ViewModifier {   @State private var isTitle: Bool = false   func body(content: Content) -> some View {     VStack {       content         .font(isTitle ? .title : .body)     }.onTapGesture {       isTitle.toggle()     }   } } struct ViewModifierTestView: View {   var body: some View {     Text("Test")       .modifier(TapToTitle())   } }
0
1
1.2k
Nov ’21
watchOS `transferFile`
The documentation states that Warning Always test Watch Connectivity file transfers on paired devices. The Simulator app doesn’t support the transferFile(_:metadata:) method. but not which error (if any) will actually be thrown when trying to execute transferFile(_:metadata:) on simulator. Could somebody share the actual error? At the moment I'm seeing this: 2022-09-03 13:47:22.742104+0900 JDict[11441:4173123] [WC] -[WCSession notifyOfFileError:withFileTransfer:] <WCSessionFileTransfer: 0x6000039ac0a0, session file: <WCSessionFile: 0x600000fce640, identifier: DB927476-A2CC-4E30-934D-EBC80D2B8CE0, file: /Users/username/Library/Developer/CoreSimulator/Devices/AE8422DC-5FCE-4319-A2B7-E04E3743D424/data/Containers/Data/Application/C738703C-C6E6-472F-8266-3F148F5468C4/tmp/CDF111BE-CD68-4B2F-95A8-BDECB7DD8A10-11441-00000516D3127532, hasMetadata: YES>, transferring: NO> with WCErrorCodeFileAccessDenied but can't be sure this is not because of another issue. I can't test on real device right now because I don't have a iOS16 phone and watchOS 9 watch right now. Further, what would be a viable strategy for development on simulator? I feel like using fixtures on the watch app with #if targetEnvironment(simulator) seems cumbersome and was wondering about a better solution. Looking forward to hearing your thoughts!
2
0
1.3k
Sep ’22
Memory leak in SwiftUI environment on Xcode 14.1 ?
Xcode 14.1 is showing a strange memory behavior for the SwiftUI environment for me. Please consider the following example import SwiftUI @main struct DoubleCheckApp: App { @Environment(\.scenePhase) private var scenePhase var body: some Scene { WindowGroup { ContentView() .environmentObject(EnvObj()) } } } class EnvObj: ObservableObject { init() { print("INIT") } deinit { print("DEINIT") } } struct ContentView: View { @State var sel: Int = 0 var body: some View { VStack { Picker(selection: $sel, label: Text("JLPT")) { ForEach(0..<3, id: \.self) { idx in Text("\(idx)").tag(idx) } }.pickerStyle(.segmented) } } } This will output INIT INIT DEINIT INIT essentially leaving two instances of EnvObj instantiated. Removing the scenePhase or the Picker implementation will result in a normal INIT/DEINIT pattern. This does not happen on Xcode 13.4.1. I couldn't test on any other versions, yet.
1
0
2.0k
Nov ’22
UserDefaults publisher for non-standard suite not working correctly
Please see the MRE below. Changing UserDefault suite to a custom one doesn't update the subscription beyond the first value. public extension UserDefaults { @objc dynamic var value1: Int { get { integer(forKey: "value1") } set { set(newValue, forKey: "value1") } } static var other: UserDefaults { UserDefaults(suiteName: "other-defaults")! } } struct ContentView: View { private let sub = UserDefaults.other.publisher(for: \.value1).sink { print("SUB", $0) } var body: some View { Button("Add") { UserDefaults.other.value1 += 1 debugPrint("SET", UserDefaults.other.value1) } .onReceive(UserDefaults.other.publisher(for: \.value1)) { debugPrint("UI", $0) } } } Only the SwiftUI onReceive subscription is working. SUB 0 "UI" 0 "SET" 1 "UI" 1 "SET" 2 "UI" 2 It works (though with multiple calls) if I set the standard UserDefaults suite. struct ContentView2: View { private let sub = UserDefaults.standard.publisher(for: \.value1).sink { print("SUB", $0) } var body: some View { Button("Add") { UserDefaults.standard.value1 += 1 debugPrint("SET", UserDefaults.standard.value1) } .onReceive(UserDefaults.standard.publisher(for: \.value1)) { debugPrint("UI", $0) } } } SUB 0 "UI" 0 SUB 1 SUB 1 "SET" 1 "UI" 1 "UI" 1 SUB 2 SUB 2 "SET" 2 "UI" 2 "UI" 2
0
0
2k
Nov ’22
NavigationStack and toolbar incompatibility
I have the following view setup. A content view with TextField in the toolbar position .principal (so, inside the NavigationBar in iOS) and a button that toggles focus on the TextField. As well as an enclosing view handling some navigation. struct FocusStateView: View { @FocusState private var isFocused: Bool @State private var username = "Anonymous" var body: some View { VStack { Button("Toggle Focus") { isFocused.toggle() } } .toolbar { ToolbarItem(placement: .principal) { TextField("Enter your username", text: $username) .focused($isFocused) } } } } struct NavigationWrapper: View { @State private var path = NavigationPath() var body: some View { NavigationStack(path: $path) { FocusStateView() .navigationDestination(for: Int.self) { _ in ContentView() } } } } This setup doesn't work unless either the .navigationDestination modifier is moved inside of FocusStateView or the TextField is moved from the toolbar into the VStack. So the following would be working: ```swift struct FocusStateView: View { @FocusState private var isFocused: Bool @State private var username = "Anonymous" var body: some View { VStack { Button("Toggle Focus") { isFocused.toggle() } } .toolbar { ToolbarItem(placement: .principal) { TextField("Enter your username", text: $username) .focused($isFocused) } } .navigationDestination(for: Int.self) { _ in ContentView() } } } struct NavigationWrapper: View { @State private var path = NavigationPath() var body: some View { NavigationStack(path: $path) { FocusStateView() } } } This looks like a bug to me, but please let me know if I'm handling something in the wrong way. Essentially I would like to keep all the navigation related logic in NavigationWrapper if possible.
0
0
579
Apr ’23
iOS AppIntents “Unable to determine value type for type” when AppEnum belongs to Swift Package
Sorry if I'm in the wrong category for this :pray: Please see this MRE for clarity: https://github.com/MartinP7r/IntentTest (I used the example code from https://developer.apple.com/wwdc22/10032 except for deprecation warnings) The compiler throws an error Unable to determine value type for type IntentPackage.Shelf. According to comments in this question it's because the type I'm extending to AppEnum is not in the app target's module, but in a Swift Package. And yes, copying Shelf into the target will solve the issue, but I really don't like having to duplicate the types just to make it work and was wondering if there's any way to just use the type from the Swift package and only add the AppEnum conformance in the main target.
1
0
394
Feb ’24