Post

Replies

Boosts

Views

Activity

Reply to List with Bindings from ObservedObject
Apple's Scrumdinger sample - https://developer.apple.com/tutorials/app-dev-training/getting-started-with-scrumdinger uses a function to generate a binding. In your case it would be like this: struct Todo: Identifiable {      let id = UUID()      var title: String      var isDone = false } class TodoStore: ObservableObject {     @Published var todos: [Todo] = [.init(title:"Test")] } struct ListRow: View {      @Binding var todo: Todo      var body: some View {           Button(action: {                self.todo.isDone.toggle()           }) {             Text("\(todo.title) \(todo.isDone.description)")           }      } } struct ContentView: View {      @StateObject var todoStore = TodoStore()      var body: some View {           List(todoStore.todos) { todo in                ListRow(todo: binding(for: todo))           }      } // from Scrumdinger sample app     private func binding(for todo: Todo) - BindingTodo {         guard let scrumIndex = todoStore.todos.firstIndex(where: { $0.id == todo.id }) else {             fatalError("Can't find scrum in array")         }         return $todoStore.todos[scrumIndex]     } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Apr ’21
Reply to Shared App Groups cache not writable
Just wanted to share that I noticed a bug in the above old code sample, the second append was done on the wrong variable, here it is fixed and updated: guard let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: group) else { return } var cachesURL = url.appendingPathComponent("Library", isDirectory: true) cachesURL = cachesURL.appendingPathComponent("Caches", isDirectory:  false) Right now I'm struggling to get a disk URLCache to write to the group container, it fails with: 2021-05-24 18:46:55.879431+0100 URLCacheTestApp[95367:2519466] [logging-persist] cannot open file at line 44499 of [02c344acea] 2021-05-24 18:46:55.879495+0100 URLCacheTestApp[95367:2519466] [logging-persist] os_unix.c:44500: (0) open(/Users/me/Library/Group%20Containers/group.com.myco.MyApp/Library/Caches/Cache.db) - Undefined error: 0 2021-05-24 18:46:55.879567+0100 URLCacheTestApp[95367:2519466] NetworkStorageDB:_openDBReadConnections: failed to open read connection to DB @ /Users/me/Library/Group%20Containers/group.com.myco.MyApp/Library/Caches/Cache.db.  Error=14. Cause=unable to open database file
Topic: App & System Services SubTopic: Core OS Tags:
May ’21
Reply to Notification/callback mechanism
XPC is bidirectional. Just use setExportedInterface and setExportedObject in your client. Then in the server when you call a method on the remoteObjectProxy you will receive the method call in the exported object in the client. FYI this is how apps that use CoreLocation receive location updates from the locationd daemon. Use Hopper on the CoreLocation framework and take a look at _CLLocationManagerRoutineProxy createConnection for more detail. `/* @class _CLLocationManagerRoutineProxy */ -(void)createConnection { rbx = self; rdi = self->_connection; if (rdi != 0x0) { [rdi release]; *(rbx + 0x18) = 0x0; } rax = [NSXPCConnection alloc]; rax = [rax initWithMachServiceName:@"com.apple.locationd.routine" options:0x1000]; *(rbx + 0x18) = rax; if (rax != 0x0) { [*(rbx + 0x18) setExportedInterface:[NSXPCInterface interfaceWithProtocol:@protocol(CLLocationManagerRoutineClientInterface)]]; [*(rbx + 0x18) setExportedObject:rbx]; r14 = [*(rbx + 0x18) exportedInterface]; r13 = objc_opt_class(@class(NSArray)); objc_opt_class(@class(CLLocation)); [r14 setClasses:[NSSet setWithObjects:r13] forSelector:@selector(didUpdateLocations:) argumentIndex:0x0 ofReply:0x0]; rdx = [NSXPCInterface interfaceWithProtocol:@protocol(CLLocationManagerRoutineServerInterface)]; [*(rbx + 0x18) setRemoteObjectInterface:rdx]; r14 = [*(rbx + 0x18) serviceName]; rdi = *(rbx + 0x18); var_78 = *__NSConcreteStackBlock; *(&var_78 + 0x8) = 0xffffffffc2000000; *(&var_78 + 0x10) = sub_911b; *(&var_78 + 0x18) = 0x71d40; *(&var_78 + 0x20) = r14; [rdi setInterruptionHandler:rdx]; rdi = *(rbx + 0x18); var_50 = *__NSConcreteStackBlock; *(&var_50 + 0x8) = 0xffffffffc2000000; *(&var_50 + 0x10) = sub_9133; *(&var_50 + 0x18) = 0x71d40; *(&var_50 + 0x20) = r14; [rdi setInvalidationHandler:&var_50]; [*(rbx + 0x18) resume]; } if ([rbx updating] != 0x0) { [[[rbx connection] remoteObjectProxy] startUpdatingLocation]; } return; } `
Jun ’21
Reply to Notification/callback mechanism
There is info on how to do this in the docs here: https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingXPCServices.html#//apple_ref/doc/uid/10000172i-SW6-SW15 See the note that says: Note: If you want to allow the helper process to call methods on an object in your application, you must set the exportedInterface and exportedObject properties before calling resume. These properties are described further in the next section.
Jun ’21
Reply to When to purge the persistent history?
Hi I'm not talking about purging all the history, only the history that is no longer needed because the NSCoreDataCoreSpotlightDelegate has already moved past it. As explained in the link I included (included again below), we have to purge the unneeded history otherwise we are wasting disk space. Purge History Because persistent history tracking transactions take up space on disk, determine a clean-up strategy to remove them when they > are no longer needed. Before pruning history, a single gatekeeper should ensure that your app and its clients have consumed the history they need. From Consuming Relevant Store Changes
Topic: UI Frameworks SubTopic: General Tags:
Jun ’21
Reply to SwiftUI: @StateObject never deinitialized
In SwiftUI we don't use view model objects. The View structs (or custom @State structs) hold the data that SwiftUI uses to diff and update the screen. View models are a UIKit pattern don't use it in SwiftUI, if you do then you'll add an unnecessary level of indirection and slow SwiftUI down and lose a lot of the magic behaviour.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Dec ’21
Reply to ForEach Breaks Data Binding
The ForEach View cannot not work with indicies for dynamic data, it requires identifiers which is why we supply it with an array of Identifiable data. This is so that it can calculate inserts, moves and deletions which obviously is impossible with an array of indicies which will in the case of moving 5 items around the indices will still be 0-4.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Feb ’22
Reply to SwiftUI EditButton problem in Xcode 12 beta
The problem is ForEach with id: \.self for a dynamic array of value types is a major mistake unfortunately made by many developers, anyone know why? The documentation states that id needs to be "The key path to the provided data’s identifier." E.g. id: \.uniqueIdentifier, or preferably conform your model struct to Identifiable and implement either let id = UUID() or var id: String { return a calculated id from other vars }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Apr ’22
Reply to multiple background requests
Use one session, according to Use Background Sessions Efficiently I noticed if you init a session with a config with the same identifier you will actually get the previous instance. I assume you have to set a taskDescription on the task to be able to identify it in .backgroundTask() on the Scene, where presumably you have to retrieve all the completed tasks from the session and deal with the results.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’22