Posts

Post not yet marked as solved
1 Replies
There’s many ways you can approach this. At a surface level I thought plucky was doing DNS & HTTP filtering by acting as a proxy. But on closer look, it looks to be implemented as a browser plugin. For subdomain/domain filtering, you can look at implementing content blocking in a safari extension: https://developer.apple.com/documentation/safariservices/creating_a_content_blocker To implement the HTML content blocking stuff, you’d probably want to look into DOM rewriting within the safari extension. At least it all seems pretty straight forward to implement.
Post not yet marked as solved
1 Replies
Put both views in a Pager view? Then add some condition for displaying the second view after validating the form contents in the first view.
Post not yet marked as solved
1 Replies
Modern sites will give you the information you need in the meta tags. So as an example, Apple grabs site meta image tiles, description and has a webkit screenshot of a website when you paste a link in iMessage. There’s really no reason you need to something beyond SwiftSoup to parse out the meta tags for you. Really, you can just grab the site meta description for that page and use some favicon or other img meta that the site owner has probable already done. I’m trying to keep things simple for you since this is an entire field. Unless you’re looking to summarize large amounts of text then you’re going down the road of needing ML.
Post not yet marked as solved
2 Replies
I just encountered and implemented this today actually. Your arrayGardenChildren shouldn’t return an optional per the compiler error. So that should be easy to fix. So I setup a SectionedFetchRequest<Folder, Note>. My example is similar but trickier. So I think if you wanted to do it on the children where its the same object type. Also your SectionedFetchRequest, you can try looking at it from a different perspective. You’re going down the right path of handling the optional parent. But instead of filtering via the sectionIdentifier, maybe you should just add a predicate. @SectionedFetchRequest private var notes: SectionedFetchResults<Folder, Note> ForEach(notes) { folder in DisclosureGroup(content: { ForEach(section) { note in NavigationLink(destination: NoteView(note: note), label: { NoteRow(note: note)})}}, label: { FolderRow(folder: folder.id) })
Post not yet marked as solved
2 Replies
So you have a few problems. The other post noted some stuff. But to answer your direct question, you have no data because the NSPersistentContainer is held and being instantiated in a StateObject. You should instantiate it in a more global sense, such as in AppDelegate or give it its own class so you instantiate it only once. I’ll point out other things, when you’re creating a new account, you probably want to be saving the context in the same scope and not have that in a separate function (saveAccountData). As the other poster mentioned. You need to figure out a better structure for setting up the PersistentContainer first. Then you can figure out if you want to use @FetchedRequest in the views and/or implement NSFretchedController on some view model.
Post not yet marked as solved
1 Replies
If you’re having to try and make modifications to fetchRequests, then you should probably be using fetchedresultscontroller. It’s kind of the purpose of it and handles your use-case.
Post not yet marked as solved
2 Replies
You all are overcomplicating things. Apple for the most part abides by the Oauth standard. Without messing around with things too much, the default response_type for Authentication Request is {code, id_token, state, user}. You can parse user for the PII you want. You set response_mode to form_post so expect a POST request containing Authorization Response parameters. After that you can validate and exchange the code. Store user information and the server can execute a redirect to the user. Like I said, Apple’s implementation is nearly the same as everyones’s. The only difference is they go out-of-spec and include a user struct.
Post not yet marked as solved
3 Replies
So one thing to keep in mind, NSManagedObjectContexts are fairly cheap to create. However, you will have the overhead of having to keep track of your child contexts - and especially implement guards to disallow cross context access of NSManagedObjects. So right off the bat, you should not be using any privateQueueConcurrencyType/Background Context for any user-facing interface. Mostly, operations performed on a background context aren't finalized until they're merged against the main persistent store. Basically you'll run into anomalous behavior if not crashes operating on objects that haven't persisted.My recommendation is to keep using that background context for large transactions, but use either the main viewContext or a child context w/ mainQueueConcurrencyType as a read-only fetch view into the persistent store. Then with the background context, you can perform create/update transactions without blocking the UI.Here's some snippets on how I've set up my background contexts. Side-note: you kinda have to use privateQueueConcurrencyType anyways if you want to support CloudKit+CoreData as I've discovered through testing.Creating background context, do your usual context.perform &amp; save func newChildCreateContext(type: NSManagedObjectContextConcurrencyType = .privateQueueConcurrencyType, mergesChangesFromParent: Bool = true) -&gt; NSManagedObjectContext { let context = NSManagedObjectContext(concurrencyType: type) context.parent = self context.name = "privateCreateContext" context.transactionAuthor = appTransactionAuthorName context.automaticallyMergesChangesFromParent = mergesChangesFromParent return context }Observe the NSManagedObjectContextDidSave notification from NotificationCenter. Merge the changed objects and the main context should resolve everything. updateChangeObserver = NotificationObserver(name: .NSManagedObjectContextDidSave, object: updateContext) updateChangeObserver.onReceived = mergeUpdateObjects private func mergeUpdateObjects(notification: Notification) { DispatchQueue.main.async { [unowned self] in self.contextDidSave(self.updateContext, note: notification) } } func contextDidSave(_ context: NSManagedObjectContext, note: Notification) { guard context === createContext || context === updateContext else { return } context.perform { context.mergeChanges(fromContextDidSave: note) } }Signal to your FetchedResultsController refresh its fetchedObjects after the merge via some other NotificationCenter observer or something. Refresh Fetched Objects on your main context controller via a NotificationCenter call or something after the merge. Changes should be reflected in the UI non-blocking.func refreshFetchedObjects() { fetchedResult.fetchedObjects?.forEach({ $0.objectWillChange.send() }) fetchedResult.managedObjectContext.refreshAllObjects() }Also another note, if you're adding a constant amount of objects - are you doing it through the new NSBatchInsertRequest operation? If you aren't already, I've found the new operation to be incredibly performant. You just have to make sure you merge the changes against the main context. public func executeAndMergeChanges(using batchInsertRequest: NSBatchInsertRequest) throws { batchInsertRequest.resultType = .objectIDs let result = try execute(batchInsertRequest) as? NSBatchInsertResult let changes: [AnyHashable: Any] = [NSInsertedObjectsKey: result?.result as? [NSManagedObjectID] ?? []] NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [self]) }
Post not yet marked as solved
3 Replies
If the issue is that the UI is blocked during transactions, why not just perform the writes onto a child private queue context as you've mentioned - then merge it against the main context. The fetch results controller should against the source of truth which is the main context.
Post not yet marked as solved
2 Replies
Give something like this a try:func syncLocations() { var batchCreate: [[String: Any]] = [] for location in remoteLocations { if let objectID = locationDataSource.performFetchObjectID(Location.requestLocationStruct(location)) { let updateObj = locationDataSource.updateContext.object(with: objectID) as! Location let (latitude, longitude) = invalidCoordinates(updateObj.provider, updateObj.slug) updateObj.latitude = latitude updateObj.longitude = longitude locationDataSource.saveUpdateObject() } else { let (latitude, longitude) = invalidCoordinates(location.provider, location.slug!) batchCreate.append( [ "uniqueID": UUID().uuidString, "title": location.title, "name": location.name ?? "", "slug": location.slug ?? "", "subtitle": location.subtitle ?? "", "locale": location.locale ?? "", "provider": location.provider, "latitude": latitude, "longitude": longitude ]) } } let request = NSBatchInsertRequest(entityName: Location.entityName, objects: batchCreate) locationDataSource.performBatchInsert(request, "location") } ... func performBatchInsert(_ request: NSBatchInsertRequest, _ author: String = appTransactionAuthorName) { do { createContext.transactionAuthor = author try createContext.executeAndMergeChanges(using: request) } catch { print(error) } } extension NSManagedObjectContext { public func executeAndMergeChanges(using batchInsertRequest: NSBatchInsertRequest) throws { batchInsertRequest.resultType = .objectIDs let result = try execute(batchInsertRequest) as! NSBatchInsertResult let changes: [AnyHashable: Any] = [NSInsertedObjectsKey: result.result as? [NSManagedObjectID] ?? []] NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [self]) } }The batch insert request basically wants an array of objects that are themselves an array of property key-values. As such, you'll need to make sure the JSON decodes to [[String: Any]]
Post marked as solved
13 Replies
Not sure you can feature-gate this since it's natively offered by Apple... using their iCloud services. What happens if you just remove the cloud descriptor?
Post not yet marked as solved
4 Replies
So from a local perspective with your scenario - client-&gt;apple and apple-&gt;client are the same. There's no client token exchange to be done, so the auth and token flow occur in a single flow. The logic is fail-close, either the user auths against apple and gets an initial token or the auth fails and no initial token. Because of that aspect, you just need to implemnt logic to store and cache the identity token as soon as the auth flow finishes. I don't see a way for the flow to auth a client and *not* respond with the identity token.With the identity token cached, have the user do a subsequent auth against your server wherein, presumably you've set up the server-side for Sign in with Apple, you can validate the identity of the user. Afterwards, it's just between your server and apple at that point.Apple can probably solve this by giving you a 1 hour window after first auth to perform a re-auth to retrieve the email address. At the same time, if all this is intentional then I have to give praise. Way too many people are collecting user PII unnecessarily and abusing the user's right to privacy.
Post not yet marked as solved
17 Replies
Here's a condensed implementation without doing that much other than rendering CIFilter on images. I have another MTKView that's actually running a compute pipeline and I banged my head a bit figuring out how to organize the code. Mainly the pattern sorta expect you to instantiate everything and leaving the Coordinator to handle actual delegation. However, for an MTKView, you are stuck either instantiating everything within the Coordinator itself or writing an additional Renderer Coordinator class to instantiate everything within. I didn't feel like going down the separate renderer route, so I just passed MTKView straight into the Coordinator and do the typical setup there.struct MTKMapView: UIViewRepresentable { typealias UIViewType = MTKView var mtkView: MTKView func makeCoordinator() -&gt; Coordinator { Coordinator(self, mtkView: mtkView) } func makeUIView(context: UIViewRepresentableContext&lt;MetalMapView&gt;) -&gt; MTKView { mtkView.delegate = context.coordinator mtkView.preferredFramesPerSecond = 60 mtkView.backgroundColor = context.environment.colorScheme == .dark ? UIColor.white : UIColor.white mtkView.isOpaque = true mtkView.enableSetNeedsDisplay = true return mtkView } func updateUIView(_ uiView: MTKView, context: UIViewRepresentableContext&lt;MetalMapView&gt;) { } class Coordinator : NSObject, MTKViewDelegate { var parent: MetalMapView var ciContext: CIContext! var metalDevice: MTLDevice! var metalCommandQueue: MTLCommandQueue! var mtlTexture: MTLTexture! var startTime: Date! init(_ parent: MetalMapView, mtkView: MTKView) { self.parent = parent if let metalDevice = MTLCreateSystemDefaultDevice() { mtkView.device = metalDevice self.metalDevice = metalDevice } self.ciContext = CIContext(mtlDevice: metalDevice) self.metalCommandQueue = metalDevice.makeCommandQueue()! super.init() mtkView.framebufferOnly = false mtkView.clearColor = MTLClearColor(red: 0, green: 0, blue: 0, alpha: 0) mtkView.drawableSize = mtkView.frame.size mtkView.enableSetNeedsDisplay = true } func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) { } func draw(in view: MTKView) { guard let drawable = view.currentDrawable else { return } let commandBuffer = metalCommandQueue.makeCommandBuffer() let inputImage = CIImage(mtlTexture: mtlTexture)! var size = view.bounds size.size = view.drawableSize size = AVMakeRect(aspectRatio: inputImage.extent.size, insideRect: size) let filteredImage = inputImage.transformed(by: CGAffineTransform( scaleX: size.size.width/inputImage.extent.size.width, y: size.size.height/inputImage.extent.size.height)) let x = -size.origin.x let y = -size.origin.y self.mtlTexture = drawable.texture ciContext.render(filteredImage, to: drawable.texture, commandBuffer: commandBuffer, bounds: CGRect(origin:CGPoint(x:x, y:y), size: view.drawableSize), colorSpace: CGColorSpaceCreateDeviceRGB()) commandBuffer?.present(drawable) commandBuffer?.commit() } func getUIImage(texture: MTLTexture, context: CIContext) -&gt; UIImage?{ let kciOptions = [CIImageOption.colorSpace: CGColorSpaceCreateDeviceRGB(), CIContextOption.outputPremultiplied: true, CIContextOption.useSoftwareRenderer: false] as! [CIImageOption : Any] if let ciImageFromTexture = CIImage(mtlTexture: texture, options: kciOptions) { if let cgImage = context.createCGImage(ciImageFromTexture, from: ciImageFromTexture.extent) { let uiImage = UIImage(cgImage: cgImage, scale: 1.0, orientation: .downMirrored) return uiImage }else{ return nil } }else{ return nil } } } }
Post not yet marked as solved
2 Replies
Sad nobody responded.What I ended up doing was creating several Core Data configurations:* Cache* Cloud* LocalCloud of course has the syncing enabled on it. So in your scenario, users can start off on Local and have it sync against the Cloud configuration in the background. Are you actually storing the entire file contents within Core Data? If so, you might want to move to a model of storing just a URI to an iCloud document, after-which a user accessing it can trigger a separate iCloud sync.I'm also fairly sure I saw documentation that there is a hard restraint on cloudkit record sizes as well.
Post not yet marked as solved
4 Replies
It looks to be by design, for privacy &amp; security reasons. You have a 600 second window on the identity token to cache it on the device and later push it up. Then subsequently cross-check the token with the identifier thats in that jwt's sub. But the flow is similar to what you'd do with Storekit verifications.Otherwise, there doesn't look to be an easy way for the user to flush the authorization device-side.