Post

Replies

Boosts

Views

Activity

Reply to Preferential access for blind users?
There are a wide variety of vision impairments that a user might have, and knowing whether a user is specifically blind is not within the scope of the Accessibility frameworks. If you really want to limit it to just blind users, you may need to have some way of marking user accounts for special access, and then invite such users to contact you directly to get their account marked accordingly. However, you can check whether a user has certain accessibility. For example, you could check UIAcessibility.isVoiceOverRunning to see if the user has VoiceOver enabled, and adjust the features in your app accordingly. Be aware that many blind users likely have VoiceOver enabled, but other vision-impaired-but-not-completely-blind users may also enable VoiceOver. Further, any user can enable VoiceOver (even non-blind users), so if you gate access to features in your app based on whether VoiceOver is active, be aware that some non-vision-impaired users may use this to gain access to that feature.
May ’24
Reply to Can CryptoKit encrypt or decrypt streams?
@eskimo That makes sense; in particular, if I'm decrypting content and streaming it out over the network as I go, I may end up streaming out invalid information, with no way to "take it back" once I get to the authentication tag and realize that it's invalid. That is certainly a case where streaming could go wrong. In my case, I'm just trying to encrypt a large video file on disk. It may be as large as 300MB. Currently, we're using OpenSSL to read a chunk, encrypt it, and write it to a local file on disk. If authentication fails at the end, then we just delete the entire file; nobody's going to be working with this intermediate data. We do this iteratively so that I don't end up with 300 MB of plaintext and 300 MB of ciphertext both in memory at the same time; that's likely to kill my app. I could use memory mapped Data to avoid loading the full plaintext input into memory, but with the current APIs I don't see any way to avoid having 300 MB of ciphertext given back to me. Perhaps an API that could take a file URL to write the complete output to would be sufficient?
Feb ’24
Reply to dateSet forecastDaily always returning 404 for past 12 hours has been working for months
We were also running into this. We wanted the daily weather for just today, so we were doing this: try await weatherService.weather(for: location, including: .current, .daily(startDate: Date(), endDate: Date()) ) And as of a few days ago, that started giving back errors. I've found, though, that adjusting the endDate forward seems to fix it. At the moment, I'm just advancing it by 86400 seconds and then ignoring the possible data for tomorrow, but there may be a better way to do that. The API docs aren't particularly clear about what time should be used on the date objects passed to .daily(). Does it need to include the start of the specified day? Noon? I assumed it would give back the weather for any day that was even partially covered by the request, but that appears to no longer be the case.
Feb ’23
Reply to Propagate a @Published value from a Core Data ManagedContext
As the code is written above, the problem would be that this… DispatchQueue.main.async { // ... self.status = "X" sleep(3) self.status = "bar" } is blocking the main thread. The @Published var may very be sending its updates, but because the main thread is blocked, you can't actually see that update in the UI. When you push a change to a @Published var, it sends a willSet event that lets the UI record the previous value. It then schedules an update on the next pass of the run loop to compare the previous value to the current value. That lets it schedule an animation from the previous state to the current state, for example. But as you've got the code written there, the main thread is blocked until the entire operation is done. That means that UI will never update to see "X" in the status field; by the time that next run loop pass is actually able to run, we're already to "bar". I would look at whether it's possible to move the long-running blocking operation to a background thread. You could then either use a completion handler to finish updating the UI, or wrap it in an async function. That is, I'm suggesting you use one of the two following patterns: // Option A (Modern Concurrency) Task { @MainActor in self.status = "X" await runLongOperation(input: "some input here") self.status = "bar" } // Since this is an async function, it will never run // on the main thread unless specifically annotated // with @MainActor. We haven't done that, so this // automatically runs in the background. func runLongOperation(input: String) async { sleep(3) } or... // Option B (Legacy Concurrency) DispatchQueue.main.async { self.status = "X" runLongOperation(input: "some input", completion: { DispatchQueue.main.async { self.status = "bar" } } } func runLongOperation(input: String, completion: @escaping ()->Void) { DispatchQueue.global().async { sleep(3) completion() } }
Aug ’22
Reply to Installing Xcode 14 beta 3 breaks Xcode 13 simulators?
It appears that this has been fixed with an updated build of Xcode 14.0 b3. From the release notes: Fixed: After installing Xcode 14 beta 3, Xcode 13.3.1 and 13.4.1 no longer show their respective iOS Simulators. Relaunch Xcode 14 beta 3 and bring up the Platforms Preference pane. Afterwards, you can relaunch the older Xcode to get the correct Simulators. (96100752) The original beta 3 build was version 14A5270e, but it appears the current one is 14A5270f.
Jul ’22
Reply to Mac app via TestFlight requires user to enter password for keychain
Thanks, Quinn. That's very helpful I assume that if I have an item in the file-based keychain, then I won't find it if I query with kSecUseDataProtectionKeychain = true. So to migrate from the file-based keychain to the data protection keychain, I would need to do the following: First check if it's in the data protection keychain If not, check if it's in the file-based keychain If found there, save a copy to the data protection keychain Optionally, delete it from the file-based keychain Does that sound correct?
Feb ’22
Reply to How I access managedObjectOriginal_ in Swift using Generated Classes?
I added an ObjC extension to NSManagedObject to make it easier to call these "managedObjectOriginal_" methods: @implementation NSManagedObject (CoreDataOriginalImplementations) (void)setValueViaOriginalCoreDataMethod:(id)value forKey:(NSString *)key {     NSString *capitalizedFirstLetter = [[key substringToIndex:1] capitalizedString];     NSString *remainder = [key substringFromIndex:1];     NSString *newSelectorName = [NSString stringWithFormat:@"managedObjectOriginal_set%@%@:",                                  capitalizedFirstLetter, remainder];          SEL newSelector = NSSelectorFromString(newSelectorName);     typedef void (*CoreDataSetter)(id, SEL, id);     CoreDataSetter impl = (CoreDataSetter)[self methodForSelector:newSelector];          impl(self, newSelector, value); } (id)getValueViaOriginalCoreDataMethodForKey:(NSString *)key {     NSString *newSelectorName = [NSString stringWithFormat:@"managedObjectOriginal_%@",                                  key];     SEL newSelector = NSSelectorFromString(newSelectorName);     typedef id (*CoreDataGetter)(id, SEL);     CoreDataGetter impl = (CoreDataGetter)[self methodForSelector:newSelector];     return impl(self, newSelector); } @end Then you can call it in Swift like this: class Person: NSManagedObject { 	var department: Department? { 		get { 			let coreDataValue = self.getValueViaOriginalCoreDataMethod(for: "department") as? Department 			/* Do other stuff here */ 			return coreDataValue 		} 		set { 			/* Do other stuff here */ 			self.setValueViaOriginalCoreDataMethod(newValue, forKey: "department") 		} 	} }
Jul ’20
Reply to Notarization error 1048
I just ran into this. I only have one account in Xcode, I have removed it and re-added it. All contracts are signed. Still getting the (1048) issue. I've been able to work around it by using altool manually, but that's annoying. I filed FB8048743 with more details.
Jul ’20