CloudKit method call hung up - ios

When app starts some preliminary process take place. Sometimes it is done quickly in some second, and sometimes It does not end, but without any error it hung up.
I.e. at launch client always fetch the last serverChangedToken. and sometimes it just hung up it does not complete. I am talking about production environment, developer works well. So this route get called, but some times it does not finishes. Any idea why? I do not get any error, timeout.
let fnco = CKFetchNotificationChangesOperation(previousServerChangeToken: nil)
fnco.fetchNotificationChangesCompletionBlock = {newServerChangeToken, error in
if error == nil {
serverChangeToken = newServerChangeToken
dispatch_sync(dispatch_get_main_queue(), {
(colorCodesInUtility.subviews[10] ).hidden = false
})
} else {
Utility.writeMessageToLog("error 4559: \(error!.localizedDescription)")
}
dispatch_semaphore_signal(sema)
}
defaultContainer.addOperation(fnco)
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)
I know it is not recommended to use semaphores to control flow of the CloudKit method calls.
Do you think the last two line can be swapped? First dispatch_semaphore_wait and then addOperation be called?
Strange that app worked for iOS 8, this bug arise only in iOS 9.

Adding the following line of code will probably solve your problem:
queryOperation.qualityOfService = .UserInteractive
In iOS 9 Apple changed the behavior of that setting. Especially when using cellular data you could get the behaviour you described.
The documentation states for the .qualityOfService this:
The default value of this property is NSOperationQualityOfServiceBackground and you should leave that value in place whenever possible.
In my opinion this is more a CloudKit bug than a changed feature. More people have the same issue. I did already report it at https://bugreport.apple.com

Related

ambiguous for type lookup in this context when -com.apple.CoreData.ConcurrencyDebug 1 is active

The code below runs perfectly fine when I have the above parameter turned off in my Scheme. When it is turned on I get a 'Group' is ambiguous for type lookup in this context crash error. on the line "let currentGroup = context.object(with: groupID) as? Group"
I've checked my project and there is no duplicate reference to Group NSManagedObject.
let context = CoreDataStack.shared.newPrivateContext()
if reset {
AppDefault.current_ListGroup = nil
}
if let groupID = AppDefault.current_ListGroup,
let currentGroup = context.object(with: groupID) as? Group {
return currentGroup.objectID
} else {
Can someone help me figure out why it works with the .ConcurrencyDebug 1 off but crashes when it is on?
Thanks in Advance
When concurrency debugging is on, the app will crash any time you break the concurrency rules. Breaking the rules on its own doesn't always crash the app-- but with debugging enabled, you're saying that you want to crash as soon as you break the rules, even if the app would work normally without debugging. This is a good thing, because breaking the rules will probably make the app crash eventually even if it doesn't happen right now.
How you're breaking the rules here is:
You're creating a new private queue context with newPrivateContext.
You're using that context without calling perform or performAndWait.
With a private queue context, you must use one of those functions whenever you use the context. Really the only time you don't have to use one of those is if you're using main queue concurrency and you know that your code is running on the main queue. You can sometimes get away with not doing that, if everything is just right, but concurrency debugging will stop you immediately. That's what you're seeing.

AudioSession maximumInputNumberOfChannels returning 0

I made an iOS plugin that captures audio data and forwards it along to a listener in the form of a byte stream. It was working flawlessly in an emulator and on various devices, but on an iPhone 6 running iOS 11.3 it is crashing during initialization. I've tracked the problem to this code:
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(AVAudioSessionCategoryPlayAndRecord)
try session.setPreferredInputNumberOfChannels(1) // This is the line that is throwing
try session.setPreferredIOBufferDuration(65)
} catch {
print(error.localizedDescription) // Prints: The operation couldn’t be completed. (OSStatus error -50.)
return -1
}
As the comment shows, the error is being caused by the call to session.setPreferredIOBufferDuration. Looking at the documentation, it says that the call will throw if the input number is greater than session.maximumInputNumberOfChannels, and judging from the error message, this seems to be the case. Checking that value on this phone, it is returning 0.
What would be causing that value to be 0? As far as I can tell, I don' think it's a permissions issue, as I request microphone permissions prior to the app reaching this point in the code. The only other thing I can think of is that the phone essentially has no microphone capabilities... but it's a phone, so the inclusion of a microphone seems fairly standard.
EDIT: I pulled out an iPad Air that's running iOS 12, and it's having the same issue.
I found the problem. I needed to add session.setActive(true) before trying to set the number of channels. I've never had to do that before, but I guess it's something you should do anyway just in case.
AVAudioSession.sharedInstance()
you can change it anyway,
search it?

iOS: CloudKit perform(query: ) does nothing - closure not executed

I am in process in adding CloudKit to my app to enable iCloud sync. But I ran into problem with my method, that executes query with perform method on private database.
My method worked fine, I then changed a few related methods (just with check if iCloud is available) and suddenly my perform method does nothing. By nothing I mean that nothing in perform(query: ) closure gets executed. I have breakpoint on the first line and others on the next lines but never manage to hit them.
private static func getAppDetailsFromCloud(completion: #escaping (_ appDetails: [CloudAppDetails]?) -> Void) {
var cloudAppDetails = [CloudAppDetails]()
let privateDatabase = CKContainer.default().privateCloudDatabase
let query = CKQuery(recordType: APPID_Type, predicate: NSPredicate(format: "TRUEPREDICATE"))
privateDatabase.perform(query, inZoneWith: nil) { (records, error) in
if let error = error {
print(error)
completion(nil)
} else {
if let records = records {
for record in records {
let appId = record.object(forKey: APPID_ID_Property) as? Int
let isDeleted = record.object(forKey: APPID_ISDELETED_Property) as? Int
if let appId = appId, let isDeleted = isDeleted {
cloudAppDetails.append(CloudAppDetails(id: appId, isDeleted: isDeleted == 1))
}
}
completion(cloudAppDetails)
return
}
}
completion(nil)
}
}
My problem starts at privateDatabase.perform line, after that no breakpoints are hit and my execution moves to function which called this one getAppDetailsFromCloud. There is no error...
This is my first time implementing CloudKit and I have no idea why nothing happens in the closure above.
Thanks for help.
EDIT: Forgot to mention that this metod used to work fine and I was able to get records from iCloud. I have not made any edits to it and now it does not work as described :/
EDIT 2: When I run the app without debugger attached then everything works flawlessly. I can sync all data between devices as expected. When I try to debug the code, then I once again get no records from iCloud.
In the completion handler shown here, if there's no error and no results are found, execution will fall through and quietly exit. So, there are two possible conditions happening here: the query isn't running or the query isn't finding any results. I'd perform the following investigative steps, in order:
Check your .entitlements file for the key com.apple.dev.icloud-container-environment. If this key isn't present, then builds from xcode will utilize the development environment. If this key is set, then builds from xcode will access the environment pointed to by this key. (Users that installed this app from Testflight or the app store will always use the production environment).
Open the cloudkit dashboard in the web browser and validate that the records you expect are indeed present in the environment indicated by step 1 and the container you expect. If the records aren't there, then you've found your problem.
If the records appear as expected in the dashboard, then place the breakpoint on the .perform line. If the query is not being called when you expected, then you need to look earlier in the call stack... who was expected to call this function?
If the .perform is being called as expected, then add an else to the if let record statement. Put a breakpoint in the else block. If that fires, then the query ran but found no records.
If, after the above steps, you find that the completion handler absolutely isn't executed, this suggests a malformed query. Try running the query by hand using the cloudkit dashboard and observing the results.
The closure executes asynchronously and usually you need to wait few seconds.
Take into account you can't debug many threads in same way as single. Bcs debugger will not hit breakpoint in closure while you staying in your main thread.
2019, I encountered this issue while working on my CloudKit tasks. Thunk's selected answer didn't help me, so I guess I'm gonna share here my magic. I got the idea of removing the breakpoints and print the results instead. And it worked. But I still need to use breakpoints inside the closure. Well, what I had to do is restart the Xcode. You know the drill in iOS development, if something's not right, restart the Xcode, reconnect the device, and whatnot.

0_ os_lock_corruption_abort in NSURLProtocol

I've built a custom NSURLProtocol which is used by a WebView whilst it browses. But at seemingly random times (between a 20 seconds or a few minutes into browsing) I am getting an EXC_BREAKPOINT and the app stops running in my NSURLProtocol.
The relevant part of my NSURLProtocol is below, it's the last line which is showing the EXC_BREAKPOINT
self.mutableData = NSMutableData(data: data!)
self.response = response
self.client?.URLProtocol(self, didReceiveResponse: response!, cacheStoragePolicy: NSURLCacheStoragePolicy.Allowed)
self.client?.URLProtocol(self, didLoadData: data!)
self.client?.URLProtocolDidFinishLoading(self)
The Xcode error is visible below:
I'm totally bamboozled on this one. Does anyone have an idea what might be causing this, and how to fix it?
Thank you!
Sam
There's not enough context for me to fully understand the code here, much less guess what's wrong, but basically what's happening is that there's a lock (mutex) that has been deallocated, but is still being used somewhere down in the NSURL* stack.
This probably points to something not getting retained properly, but it is anybody's guess what or where. It might even be that your protocol is not getting retained properly, in which case you might be able to fix it by assigning your protocol object to a property on itself until after you call your last delegate method, then nulling it out.
With that said, there's reason to believe that this is a bug in the OS itself, so while you try to work around it, you should also file a bug. It will get duped to the other dozen or so bugs from other people who have asked this same question both here and on the Apple developer forums. :-)

How to fix "NSURLErrorDomain error code -999" in iOS

I've been trying to use Corona SDK's Facebook API to post the score on the game I'm developing on facebook. However, I'm having a problem with it. During the first time I try to post to facebook, I get this error after login and user authentication:
NSURLErrorDomain error code -999
Then, it won't post on facebook. What are possible causes of this error and how can I address it?
By the way, I am not using webview on my app. Just the widget api and a show_dialog listener in my Facebook class.
The error has been documented on the Mac Developer Library(iOS docs)
The concerned segment from the documentation will be:
URL Loading System Error Codes
These values are returned as the error code property of an NSError
object with the domain “NSURLErrorDomain”.
enum
{
NSURLErrorUnknown = -1,
NSURLErrorCancelled = -999,
NSURLErrorBadURL = -1000,
NSURLErrorTimedOut = -1001,
As you can see; -999 is caused by ErrorCancelled. This means: another request is made before the previous request is completed.
Just wanted to add here, when receiving a -999 "cancelled" the problem usually is one of two things:
You're executing the exact same request again.
You're maintaining a weak reference to your manager object that gets deallocated prematurely. (Create strong reference)
hjpotter92 is absolutely right, I just want to provide solution for my case. Hopefully it is useful for you as well. Here is my situation:
On log in page > press log in > pop up loading dialog > call log in service > dismiss dialog > push another screen > call another service --> cause error -999
To fix it, I put a delay between dismissing dialog and pushing new screen:
[indicatorAlert dismissWithClickedButtonIndex:0 animated:YES];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.01 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"HomeSegue" sender:nil];
});
It is strange that this issue happens on iOS 7 only.
I have faced the same error with Alamofire and it was because the certificate pinning.
The certificate wasn't valid anymore, so I had to remove it and add the new one.
Hope it helps.
In addition to what Ramon wrote, there is a third possible reason when receiving a NSURLErrorDomain -999 cancelled:
You cancelled the task while it was executing either by calling .cancel() on the datatask object or because you used .invalidateAndCancel() on the session object. If you are creating a custom session with a delegate, you should call .invalidateAndCancel() or .finishTasksAndInvalidate() to resolve the strong reference between the session and its delegate, as mentioned in the Apple Developer Documentation:
The session object keeps a strong reference to the delegate until your app exits or explicitly invalidates the session. If you don’t invalidate the session, your app leaks memory until it exits.
If you are wondering about this logging behaviour, I found the following explanation in the Apple Developer forums:
By way of explanation, back in iOS 10 we introduced a new logging system-wide logging architecture (watch WWDC 2016 Session 721 Unified Logging and Activity Tracing for the details) and lots of subsystem, including CFNetwork, are in the process of moving over to that. Until that move is fully finished you’re going to encounter some weird edge cases like this one.
I didn't use Corona SDK's Facebook API but I encountered this problem when using Alamofire, the secondRequest always cancel in execution with the error -999, according to the posts I found on internet, the reason is that session property is deinit before completion of async work since it is out of the scope, I finally solved this problem by deinit the session property manually so the compiler won't deinit it at wrong position:
class SessionManager {
var session:SessionManager?
init() {
self.session = SessionManager(configuration:URLSessionConfiguration.ephemeral)
}
private func firstRequest() {
guard let session = self.session else {return}
session.request(request_url).responseData {response in
if let data=response.data {
self.secondRequest()
}
}
private func secondRequest() {
guard let session = self.session else {return}
session.request(request_url).responseData {response in
if let data=response.data {
self.secondRequest()
}
//session will no longer be needed, deinit it
self.session = nil
}
}
Our company's app has many -999 error in iOS. I have searched around, find the reason has two, like the network task has been dealloc or the certificate isn't valid. But I have checked our code, these two aren't possible. I am using Alamofire
which is using URLSession. Luckily, our company's android app's network is normal. So we check the difference. We found the http request from iOS is Http2.0, while android is Http1.1. So we force the backend http support version down to http1.1, then -999 error count descends!!!
I think there maybe some bug in Apple's URLSession. Check the link New NSURLSession for every DataTask overkill? for some detail thoughts
Please check If you call cancel() on URLSessionDataTask to fix
NSURLErrorDomain Code=-999 "cancelled"
I was getting this error in iOS specific version of Xamarin app. Not sure the underlying cause, but in my case was able to work around it by using post method instead of get for anything passing the server context in the request body -- which makes more sense anyway. Android / Windows / the service all handle the GET with content, but in iOS app will become partially unresponsive then spit out the 999 NSUrlErrorDomain stuff in the log. Hopefully, that helps someone else running into this. I assume the net code is getting stuck in a loop, but could not see the code in question.
For my Cordova project (or similar), turns out it was a plugin issue. Make sure you're not missing any plugins and make sure they're installed properly without issue.
Easiest way to verify this is simply to start fresh by recreating the Cordova project (cordova create <path>) along with the required platforms (cordova platform add <platform name>) and add each plugin with the verbose flag (--verbose) so that you can see if anything went wrong in the console log while the plugin is being downloaded, added to project and installed for each platform (cordova plugin add cordova-plugin-device --verbose)
Recap:
cordova create <path>
cordova platform add <platform name>
cordova plugin add cordova-plugin-device --verbose
For my case, I used an upload task post that did not need body contents:
// The `from: nil` induces error "cancelled" code -999
let task = session.uploadTask(with: urlRequest, from: nil, completionHandler: handler)
The fix is to use zero byte data instead of nil,
let task = session.uploadTask(with: urlRequest, from: Data(), completionHandler: handler)
The framework documentation doesn't specify why the from bodyData is an optional type, or what happens when it is nil.
We solved this problem by reloading the web view when it failed loading.
extension WebViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
webView.reload()
}
}

Resources