Can't get iCloud metadataQuery to work - ios

I have an issue with the iCloud metadataQuery.
I am trying to fetch some documents from iCloud but when I call the NSPredicate function I get the following error in the console of Xcode:
warning: could not load any Objective-C class information from the
dyld shared cache. This will significantly reduce the quality of type
information available.
Note: I am using Swift version 2.
This is my function:
var _iCloudQuery:NSMetadataQuery!
func iCloudQuery()->NSMetadataQuery?{
if (_iCloudQuery == nil) {
_iCloudQuery = NSMetadataQuery.init()
_iCloudQuery.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope]
_iCloudQuery.predicate = NSPredicate(format: "(%K = '*')", NSMetadataItemURLKey)//
// Set observer here
NSNotificationCenter.defaultCenter().addObserver(self, selector: "processCloudQueryResults:", name: NSMetadataQueryDidFinishGatheringNotification, object: _iCloudQuery)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "processCloudQueryResults:", name: NSMetadataQueryDidUpdateNotification, object: _iCloudQuery)
}
return _iCloudQuery
}
I already figured out that processCloudQueryResults never gets fired because there are no items in icloudQuery but still there are documents in my iCloud container so there should.
This is a related topic with no solutions:
Searching for files using NSMetadataQuery does simply nothing

Related

How can I detect if a user has changed the iPhone system language settings while the app is running?

I am going to use these language changes as triggers in the code that I'm going to write.
For example:
if languageHasChanged() {
//do something
}
Register for the NSLocale.currentLocaleDidChangeNotification notification.
NotificationCenter.default.addObserver(self, selector: #selector(localeChanged), name: NSLocale.currentLocaleDidChangeNotification, object: nil)
func localeChanged() {
}
If NSLocale.currentLocaleDidChangeNotification is not available, you can store the actual Locale in applicationWillTerminate and applicationWillEnterBackground in a variable, and compare it to the locale in applicationDidBecomeActive.

Contact Framework equivalent to ABAddressBook.ABAddressBookRegisterExternalChangeCallback

I am migrating an application from the deprecated Address Book Framework to the new Contacts Framework. The application utilizes ABAddressBookRegisterExternalChangeCallback to be notified when another application changes a contact.
I am unable to find equivalent functionality in the Contacts Framework. Apple documentation says to use the default notification center with the CNContactStoreDidChangeNotification notification:
The notification posted when changes occur in another CNContactStore.
Taking Apple's advice, my code looks like this:
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "contactsChanged:",
name: CNContactStoreDidChangeNotification,
object: nil)
However, I have found two problems with this approach:
I am notified for all changes, including those made by my own application.
Notifications are spurious - I receive many notifications for a single change.
If I log the debug description of the notification when the change was made within my app, I get something like this:
NSConcreteNotification 0x7d3370e0 {name = CNContactStoreDidChangeNotification; userInfo = {
CNNotificationOriginationExternally = 1;
CNNotificationSourcesKey = (
);
}}
And if the changes are made externally:
NSConcreteNotification 0x7bf7a690 {name = CNContactStoreDidChangeNotification; userInfo = {
CNNotificationOriginationExternally = 1;
CNNotificationSourcesKey = (
);
}}
As you can see, nothing obvious with which to distinguish them.
Can anyone tell me how to get the same behavior from the Contacts Framework as one can get from ABAddressBookRegisterExternalChangeCallback?
First, I'd recommend filing a bug with Apple about the lack of a way to identify internal vs external changes in the API.
As a possible workaround, you could see if unregistering your observer before making a change and re-registering immediately afterward ensures that you miss all of your change notifications and still get all the external ones:
class ContactsThingy {
var observer: NSObjectProtocol?
let contacts = CNContactStore()
func contactStoreDidChange(notification: NSNotification) {
NSLog("%#", notification)
}
func registerObserver() {
let center = NSNotificationCenter.defaultCenter()
observer = center.addObserverForName(CNContactStoreDidChangeNotification, object: nil, queue: NSOperationQueue.currentQueue(), usingBlock: contactStoreDidChange)
}
func unregisterObserver() {
guard let myObserver = observer else { return }
let center = NSNotificationCenter.defaultCenter()
center.removeObserver(myObserver)
}
func changeContacts(request: CNSaveRequest) {
unregisterObserver() // stop watching for changes
defer { registerObserver() } // start watching again after this change even if error
try! contacts.executeSaveRequest(request)
}
}

Post NSUserDefaults changes between iOS Keyboard Extension and Containing app?

I thought I have tried everything and read every possible articles in this forum. But nothing seems to work. Here is some code snippet and some settings:
On Extension side:
let thisDefaults = NSUserDefaults(suiteName: "group.request.com")
thisDefaults?.setObject("Hello", forKey: "prevWord")
thisDefaults?.setObject("World", forKey: "word")
let success = thisDefaults?.Synchronize()
NSNotificationCenter.defaultCenter().postNotificationName("ExtensionRequestChanges", object: nil)
On Containingg app side:
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("DidReceiveRequest:", name: "ExtensionRequestChanges",
object: nil)
func DidReceiveRequest(notification: NSNotification) {
// Read defaults
let thisDefaults = NSUserDefaults(suiteName: "group.request.com")
let word = thisDefaults?.stringForKey("word")
let prevWord = thisDefaults?.stringForKey("prevWord")
...
}
On the project settings:
. registered "group.request.com" app group to both the extension and containing app
. set "RequestOpenAccess" in NSExtensionAttributes to YES
But my DidReceiveRequest function never seemed to get called! Why???
Please help.
NSNotificationCenter only works in the process it's running in. Your keyboard extension and container app are separate processes. To post interprocess notifications, you should investigate the CFNotificationCenterGetDarwinNotifyCenterAPI call, which returns a Core Foundation notification center that can post notifications between processes, or other forms of interprocess communication.

Getting the currently active keyboard language as NSLocale

I already found a lot of approaches for this but no working solution. Here's what I tried and didn't work.
(1) Simply calling primaryLanguage()
UITextInputMode().primaryLanguage
→ always returns nil :-/
(2) Subscribing to UITextInputCurrentInputModeDidChangeNotification notifications
override func viewDidLoad() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "changeInputMode:", name: UITextInputCurrentInputModeDidChangeNotification, object: nil)
}
func changeInputMode(sender : NSNotification) {
...?!
}
The notification is getting triggered but it is unclear how I can extract the current language information from the notification.
(3) Using activeInputModes()
let localeIdentifier = UITextInputMode.activeInputModes().first as? UITextInputMode
var locale:NSLocale = NSLocale(localeIdentifier: localeIdentifier.primaryLanguage!)
println("Input Mode Language \(localeIdentifier.primaryLanguage!)")
This always provides the same array of all available keyboards, no information on the actually active one.
How do I get the NSLocale of the currently active keyboard?
You can access the primaryLanguage from every textfield by accessing the textfields textInputMode like that:
var language = textfield.textInputMode?.primaryLanguage

In Swift, how to ivalidate NSTimer in AppDelegate when application going background?

I need to translate my iOS application from obj-c to swift. I have a NStimer in ViewController that loads metadata from shoutcast every 30 seconds, but when application resign active it stops, when enter foreground it runs again.
Edit: OK. Problem solved! I added two observers in viewDidLoad with name UIApplicationWillResignActiveNotification and UIApplicationWillEnterForegroundNotification, like below:
override func viewDidLoad() {
NSLog("System Version is \(UIDevice.currentDevice().systemVersion)");
super.viewDidLoad()
self.runTimer()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "invalidateTimer", name: UIApplicationWillResignActiveNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "runTimer", name: UIApplicationWillEnterForegroundNotification, object: nil)
}
and I made two functions. First one for run timer:
func runTimer(){
loadMetadata()
myTimer.invalidate()
NSLog("timer run");
myTimer = NSTimer.scheduledTimerWithTimeInterval(30.0, target: self, selector: "loadMetadata", userInfo: nil, repeats: true)
let mainLoop = NSRunLoop.mainRunLoop()
mainLoop.addTimer(myTimer, forMode: NSDefaultRunLoopMode)
}
and second to stop it:
func invalidateTimer(){
myTimer.invalidate()
NSLog("timer invalidated %u", myTimer);
}
I hope this can help someone. :)
I suggest you use the appropriate system for your task: https://developer.apple.com/library/ios/documentation/iphone/conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW56
Apps that need to check for new content periodically can ask the
system to wake them up so that they can initiate a fetch operation for
that content. To support this mode, enable the Background fetch option
from the Background modes section of the Capabilities tab in your
Xcode project. (You can also enable this support by including the
UIBackgroundModes key with the fetch value in your app’s Info.plist
file.)...
When a good opportunity arises, the system wakes or launches your app
into the background and calls the app delegate’s
application:performFetchWithCompletionHandler: method. Use that method
to check for new content and initiate a download operation if content
is available.

Resources