I'm new to Core Data and iCloud, but I've managed to get both working (mostly). My data is syncing between iOS devices, but I don't know when. :)
I'm trying to listen for when changes are available from iCloud so I can refresh my UI.
I set up Core Data and iCloud in my app delegate like this: http://d.pr/n/SxmZ Most of that is sample code I have applied, but it seems to work well.
In a separate view controller, where I'm displaying app data, I have set up my notification like this:
- (void)viewDidLoad
{
[super viewDidLoad];
//Register notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updatesAvailable) name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:nil];
}
- (void)updatesAvailable{
//This never fires...
NSLog(#"Update available...");
[PPStatusBar showSuccessWithStatus:#"Update available..."];
}
So here are my questions:
If all that iCloud stuff gets set up in my app delegate, does that mean it's available to use everywhere? Or do I have to re-initialize my persistent store coordinator in every view controller where I want to listen for notifications?
I am planning to re-query my entity in that updatesAvailable method, so has the data from iCloud made it all the way into the Core Data object graph by the time NSPersistentStoreDidImportUbiquitousContentChangesNotification is called?
Is it safe to assume that small, single-record changes should be propagating between two iOS devices within 10 seconds?
I have tried this between two iOS 7 devices, in addition to the iOS 7 Simulator, and still no luck. I have also managed to get iCloud key/value change listeners work great, it's just not working with Core Data.
Thanks in advance for your help. :)
It looks like the problem is in your addObserver call. The object is nil but it should be your persistent store coordinator. For example:
[notificationCentre addObserver:self
selector:#selector(CoreData_StoreDidImportUbiquitousContentChanges:)
name:NSPersistentStoreDidImportUbiquitousContentChangesNotification
object:coordinator];
Which then calls a notification handler structured like this:
- (void)CoreData_StoreDidImportUbiquitousContentChanges:(NSNotification*) notification {
}
To answer your specific questions:
The persistent store, managed object context etc will be accessible elsewhere. However, be aware that the managed object context is not threadsafe. You should only ever access it from the same thread.
The new data should be accessible at the time you receive the notification. The NSNotification object itself can also be used if you only want to know about the new data. It contains details of all changed objects grouped based on if they were created, odified or deleted.
The propagation time seems very variable. The simulator allows you to request a sync (Cmd+I) but I'm not aware of a similar mechanism on an actual device. If you are currently debugging one of the running devices however you will be able to see activity to/from iCloud in Xcode.
One further note. The import notification will come in on a different thread to your user interface. If you want to make any UI changes (eg. refreshing) then you will need to use something like this to make sure they run on the UI thread:
dispatch_async(dispatch_get_main_queue(), ^{
// Refresh UI here
});
Related
I need my iOS sender app to be aware of any changes made by the user regarding the active tracks but I cannot find any way to do so.
When the app is registered as a GCKMediaController delegate, it is notified via the mediaController(_:didUpdate) method that a change has occurred and the list of active tracks can be retrieved but nothing indicates that the update deals with active tracks change.
Moreover, my app simply provides a UIButton to the GCKMediaController tracksButton and does not instantiate a GCKMediaTracksViewController so I cannot register anything as a GCKMediaTracksViewControllerDelegate.
The last resort would be for my app to implement a custom media tracks selection view controller but I would not want to have to do that.
Thanks for your help.
During WWDC 2019 Apple introduced NSPersistentCloudKitContainer which allows for syncing of CoreData with CloudKit. It is a great addition. In iOS 13 in notes app also user is allowed to to share the entire note "FOLDER" with another user. Given that Apple uses CloudKit for Notes app, I wanted to create something similar to understand how it better works.
Apple creates com.apple.coredata.cloudkit.zone zone and basically syncs all data there into that zone if all setup conditions are met. However there is no guideline when user would like to share data. According to a former WWDC talk, sharing would be possible mainly via creating a CUSTOM ZONE. However the new NSPersistentCloudKitContainer provides no possible way to change the zone for each entity in the CoreData.
I was very happy to have found these
open func record(for managedObjectID: NSManagedObjectID) -> CKRecord?
open func records(for managedObjectIDs: [NSManagedObjectID]) -> [NSManagedObjectID : CKRecord]
open func recordID(for managedObjectID: NSManagedObjectID) -> CKRecordID?
open func recordIDs(for managedObjectIDs: [NSManagedObjectID]) -> [NSManagedObjectID : CKRecordID]
as they gave this impression that the container calls this methods to retrieve the CKRecord and hence a point to modify informations such as zone etc. but after the setup I realized when I add a new entity to my CoreData, these functions even though when overrides are not called.
My question in short is: how to take controll of how NSPersistentCloudKitContainer manages which record belongs to which zone other than com.apple.coredata.cloudkit.zone
Basically I want to display the current track on a website.
I already searched quite a bit for a possibility to get notified when player state (play/pause, track, current position) changes.
My question:
Is it possible to get notified (socket, hook call) or is the only possibility I have to call the Web API like every second and fetch the state?
I fear that I'm running into rate limits when multiple users connect their accounts and display the current track.
Nope, there's still no way to do that. To achieve what you'd like, you need to pool the Spotify API continuously.
You can however use the Spotify SDK that you can pass a function to be executed on playback state change. The SDK is incompatible with a few platforms (see supported browsers), but for those you could catch the SDK initialization error and then switch to continuous polling via the API. You will have a lot fewer requests then.
A second option would be to only update the currently playing song after the last song should have ended. When getting the playback state for the currently playing song, you could use the field duration_ms and progress_ms to calculate the remaining time of the song. Then schedule another API requests for when the song should have ended and you're good. Whether that's a good strategy for your use case or not depends on the type of playback and how often the playback changes in your app.
I hope I could help!
As of now, it seems to be possible to receive player state events with a listener:
https://developer.spotify.com/documentation/web-playback-sdk/guide/#playback-information-display
I haven't tested the Web version, I'm currently using the analogous Android APIs, and Android's seems to work for play/pause change and track change (but not for position change)
I have a monotouch application which has a timer and gets the data from the server.
Once the data is received i want to show the notification on the status bar.
It wrks fine when the app is in foreground. When the app is in background ,neither the timer nor the notification works
Please help me in rectifying this issue.
getting you app to run in the background is easy, add App registers for location updates in the info.plist, create a CLlocation singleton register for significant location change and you are done, your app will be resurrected every time there is a significant location change
When an iOS app transitions to the suspended (i. e. backgrounded) state, it stops its timers and disables locl notifications (and does some more memory optimization-related actions). A possible solution (JB only) to display user alerts while your app is in the background is to run a server (true unix server which is not bothered by an app getting backgrounded!) and use the undocumented CFUserNotificationDisplayAlert() function (just google it).
Your best chance is to extend the lifetime of your app by a little bit, by requesting a grace period in the background. As long as you receive this message during this time frame, you will be able to post the notification.
You do this by calling UIApplication.BeginBackgroundTask. This will let you run for a little bit, and the method you pass will be invoked shortly before your grace period runs out.
When you have an App with registers for location updates it seems to always run in the background to a certain extent, as you get significan location changes and you get the enter/exit regions, so you app is running code or is being waken up to run code... the problem is that the UILocalnotification doesn't trigger a sound and alert consitently ( but all the calls are displayed in the notification center... ) The big problem here is that the significan location changes, and the enter/exit regions are useless if you can not notify your user reliably.... is CFUserNotificationDisplayAlert() the only solution to trigger an alert to the user... ? does it work ? will your app be rejected if you use it ?
I got this working as follows :(Not a good design, but a working one)
Addded location support in info.plist, create a clocation manager and kept on requsting the location services. On the same loop schedule the UIlocalnotification .
It works perfectly. :)
NOTE : One issue is that it will give the user a propmpt as "This app uses your location, Do you want o allow"
I've studied some CQRS sample implementations (Java / .Net) which use event sourcing as the event store and a simple (No)SQL stores as the 'report store'.
Looks all good, but I seem to be missing something in all sample implementations.
How to handle the addition of new report stores / screens, after an application has gone in production? and how to import existing (latest) data from the event store to the new report store?
Ie:
Imagine a basic DDD/CQRS driven CRM application.
Every screen (view really) has it's own structured report store (a SQL table).
All these views get updated using handlers listening to the domain events (CustomerCreated / CustomerHasMoved, etc).
One feature of the CRM is that it can log phone calls (PhoneCallLogged event). Due to time constraints we only implemented the logging of phone calls in V1 of the CRM (viewing and reporting of who handled which phone call will be implemented in V2)
After a time running in production, we want to implement the 'reporting' of logged phone calls per customer and sales representative.
So we need to add some screens (views) and the supporting report tables (in the report store) and fill it with the data already collected in the Event Store...
That is where I get stuck while looking at the samples I studied. They don't handle the import of existing (history) data from the event store to a (new) report store.
All samples of the EventRepository (DomainRepository) only have a method 'GetById' and 'Add', they don't support getting ALL aggregate roots in once to fill a new report table.
Without this initial data import, the new screens are only updated for newly occurred events. Not for the phone calls already logged (because there was no report listener for the PhoneCallLogged event)
Any suggestions, recommendations ?
Thanks in advance,
Remco
You re-run the handler on the existing event log (eg you play the old events through the new event handler)
Consider you example ... you have a ton of PhoneCallLoggedEvents in your event log. Take your new Handles and play all the old events through it. It is then like it has always been running and will just continue to process any new events that arrive.
Cheers,
Greg
For example in Axon Framework, this can be done via:
JdbcEventStore eventStore = ...;
ReplayingCluster replayingCluster = new ReplayingCluster(
new SimpleCluster("replaying"),
eventStore,
new NoTransactionManager(),
0,
new BackloggingIncomingMessageHandler());
replayingCluster.startReplay();
Event replay is an area that is not completely documented and lacks mature tooling, but here are some starting points:
http://www.axonframework.org/docs/2.4/event-processing.html#d5e1852
https://groups.google.com/forum/#!searchin/axonframework/ReplayingCluster/axonframework/brCxc7Uha7I/Hr4LJpBJIWMJ
The 'EventRepository' only contains these methods because you only need them in production.
When adding a new denormalization for reporting, you can send all event from start to you handler.
You can do this on your development site this way :
Load your event log to the dev site
Send all events to your denormalization handler
Move your new view + handler to your production site
Run events that happened inbetween
Now you're ready