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.
Post
Replies
Boosts
Views
Activity
@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?
I'm seeing this too. However, I'm having trouble reproducing the warning in a small sample project.
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.
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()
}
}
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.
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?
I'm also seeing this; when I try to archive and upload our Mac app with Xcode 13.2.1, we get the same error. I filed FB9877768. I've also tried building and uploading with 13.2.0, and got the same problem.
I've been running into this too; it's quite annoying. Can you clarify what using "iOS style keychains" as a workaround means?
Three years later in iOS 13, I'm running into the same thing. I filed FB5746349 about it, but haven't heard anything yet.
Resolved the issue; it turns out I had another older copy of the app on the system, and ASAuthorizationController was using that one to decide whether the webcredentials: associated domain was supported. Removing that older copy of the app fixed the issue.
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")
		}
	}
}
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.
Follow-up: I talked to an engineer in the labs, and I passed along some additional logs for investigation. There wasn't anything obviously wrong with my configuration, so either there's a system bug or there's something weird about how the credentials are stored in the keychain that is causing them to not be found.
Filed FB7774028 with a sysdiagnose attached.