NSUserDefaultsDidChangeNotification and Today Extensions
From doc here:
Cocoa includes two types of notification centers:
The NSNotificationCenter class manages notifications within a single
process. The NSDistributedNotificationCenter class manages
notifications across multiple processes on a single computer.
Apparently the containing app and today extension are different processes, since when you debug today extension you want to attach containing app process, but NSNotificationCenter only work within a single process.
In order to communicate between containing app and extensions, you can use
Darwin Notify Center CFNotificationCenter
that works like NSDistributedNotificationCenter
, which is only available for osx.
The idea is use a file inside the group folder that they share. in containing app, you write the data you want to send into the file, then post a CFNotification, which will be received by today extension.
In today extension, use CFNotificationCenterAddObserver
to observer the CFNotification, upon receiving it, callback will be called, in which a NSNotification has to be posted due to callback is a C style function and "userInfo" cannot be passed in the CFNotification, after receiving this NSNotification object, it starts to read data from the file, which is used to update the today extension view in Notification center.
You can use this github code to implement force loading the today extension view. It works for me.
Here is a great post on this. http://www.atomicbird.com/blog/sharing-with-app-extensions
Another option is to use setHasContent function. When you schedule a local identifier, set has content to false to hide the view, in handleActionWithIdentifier
set it to true to show the view. This way, when you stay in notification center, you will not see the view for a moment, but when you see it, it will be the updated data.
let widgetController = NCWidgetController.widgetController()
widgetController.setHasContent(false, forWidgetWithBundleIdentifier: "YourTodayWidgetBundleIdentifier")
But I think the whole problem is a rare case, which doesn't need to be fixed since you can get the updated data reloading the notification center or switch to notification tab and switch back to today tab.
NSUserDefaultsDidChangeNotification not sent
So, SushiHangover provided perfectly working piece of code.
However, the problem was in the Info.plist
file. In order to be able to exchange the notification the Background Mode
should be enable for the app with Remote Notification
feature. It sounds like a very obvious thing to do, but none of the tutorials for exchanging data between Extension and app with User Defaults
that I read mentioned this. Perhaps, it is an obvious thing to do. But I am writing this just in case somebody might have missed this thing too.
NSUserDefaultsDidChangeNotification: What's the name Of the Key, that Changed?
As others stated, there is no way to get the info about the changed key from the NSUserDefaultsDidChange Notification. But there is no need to duplicate any content and check for yourself, because there is Key Value Observing (KVO) which also works with the NSUserDefaults, if you need to specifically be notified of a certain property:
First, register for KVO instead of using the NotificationCenter:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults addObserver:self
forKeyPath:@"nameOfThingIAmInterestedIn"
options:NSKeyValueObservingOptionNew
context:NULL];
don't forget to remove the observation (e.g. in viewDidUnload or dealloc)
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults removeObserver:self forKeyPath:@"nameOfThingIAmInterestedIn"];
and finally implement this method to receive KVO notifications
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
NSLog(@"KVO: %@ changed property %@ to value %@", object, keyPath, change);
}
Save and Load Data on Today Extensions (iOS 8)
You need to use app group identifier instead of com.*
For instance:
NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:@"group.company.appgroup"];
Don't forget to synchronise when you store data
[shared synchronize];
How to send and receive data in Today extensions
Apart from NSUserDefaults, you can use the NSNotificationCenter to send or receive data anywhere.
You need to set the observer where you can receive the data like below:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "dataReceived:", name: "SpecialKey", object: nil)
}
Funciton to catch data:
func dataReceived(notification: NSNotification) {
//deal with notification.userInfo
println(notification.userInfo)
println("Received Data")
}
And you need to define NSNotificationCenter from where you need to send the data:
NSNotificationCenter.defaultCenter().postNotificationName("SpecialKey", object: nil, userInfo: ["MyData": "Demo"])
References:
The complete guide to NSNotificationCenter
Hope it helps!
http://moreindirection.blogspot.in/2014/08/nsnotificationcenter-swift-and-blocks.html
Refreshing a Today extension view
You can use shared NSUserDefaults and observer it.
In your app:
After you update database, execute the below:
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.yourcompany.sharedDefaults"];
[userDefaults setObject:[NSDate date] forKey:@"updatedDate"];
[userDefaults synchronize];
In your Today Widget:
add a observer in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(userDefaultsDidChange:)
name:NSUserDefaultsDidChangeNotification
object:nil];
then
- (void)userDefaultsDidChange:(NSNotification *)notification {
// check updatedDate and update widget UI
}
refer: http://www.glimsoft.com/06/28/ios-8-today-extension-tutorial/
Related Topics
iOS 7 Device Token Is Different for Same Device
Change the Alpha Value of the Navigation Bar
Will Appstore Reviewers Allow Us to Use Dynamic Library in iOS8
How to Receive Push Notifications of an Other App
Collectionview with the Horizontal Scroll with Mulitple Section
Xcode 11.4. Navigation's Title Color Gone Black from Storyboard
How to Animate a Uiview with Constraints in Swift
Where to Highlight Uicollectionviewcell: Delegate or Cell
Swift: Save Video from Nsurl to User Camera Roll
Add a View on Top of the Keyboard Using Inputaccessoryview
How to Disable Custom Keyboards (Ios8) for My App
Uidatepicker Bug? Uicontroleventvaluechanged After Hitting Minimum Internal
How to Get Previous and Next Month in Calendar-Swift
Is the Function 'Dlopen()' Private API
Coreanimation - Opacity Fade in and Out Animation Not Working
Lock iOS App in Single App Mode Programmatically
Uinavigationcontroller Interactivepopgesturerecognizer Working Abnormal in iOS7
Using Apple's Reachability to Check Remote Server Reachability in Swift