iOS 4.3 support for AFNetworking - What can be the problems? - ios4

I have already an application developed with iOS 4.3+ support. I want to shift from ASIHTTPRequest
to AFNetworking but on the docs say that I should use the 0.10.x module rather than the current one. https://github.com/AFNetworking/AFNetworking#requirements
The problem with using the current code (1.x) of AFNetworking is stated to be ( https://github.com/AFNetworking/AFNetworking/issues/545 ):
ARC introduction in 1.x
Use of NSJSONSerialization
imp_implementationWithBlock() API difference
But iOS 4.3 supports ARClite, and going through the code of 1.x, I didn't come across any property using weak references that could cause problem. http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/ObjCAvailabilityIndex/_index.html
iOS 4.3 supports imp_implementationWithBlock()
There are only two references that use NSJSONSerialization, and I changed them to JSONKit calls ->
diff --git a/AFNetworking/AFHTTPClient.m b/AFNetworking/AFHTTPClient.m
index 62fc30a..3a60da5 100755
--- a/AFNetworking/AFHTTPClient.m
+++ b/AFNetworking/AFHTTPClient.m
## -24,6 +24,7 ##
#import "AFHTTPClient.h"
#import "AFHTTPRequestOperation.h"
+#import "JSONKit.h"
#import <Availability.h>
## -163,7 +164,7 ## - (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding
static NSString * AFJSONStringFromParameters(NSDictionary *parameters) {
NSError *error = nil;
- NSData *JSONData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:&error];;
+ NSData *JSONData = [parameters JSONDataWithOptions:JKSerializeOptionNone error:&error];
if (!error) {
return [[NSString alloc] initWithData:JSONData encoding:NSUTF8StringEncoding];
diff --git a/AFNetworking/AFJSONRequestOperation.m b/AFNetworking/AFJSONRequestOperation.m
index 607f247..c7367dc 100755
--- a/AFNetworking/AFJSONRequestOperation.m
+++ b/AFNetworking/AFJSONRequestOperation.m
## -21,6 +21,7 ##
// THE SOFTWARE.
#import "AFJSONRequestOperation.h"
+#import "JSONKit.h"
static dispatch_queue_t af_json_request_operation_processing_queue;
static dispatch_queue_t json_request_operation_processing_queue() {
## -66,7 +67,7 ## - (id)responseJSON {
if ([self.responseData length] == 0) {
self.responseJSON = nil;
} else {
- self.responseJSON = [NSJSONSerialization JSONObjectWithData:self.responseData options:0 error:&error];
+ self.responseJSON = [self.responseData objectFromJSONDataWithParseOptions:JKSerializeOptionNone error:&error];
}
self.JSONError = error;
Though this compiles beautifully, But i am still skeptical about doing it this way. Is this a correct way to go?

There are things you can change to get AFNetworking >= 1.0 to compile on iOS < 5, but this is not recommended, as other breaking changes may occur in subsequent releases.
But if happy with creating a fork that cannot incorporate mainline bug fixes and features, then there's nothing inherently wrong with your approach.

Related

macOS High Sierra 10.13 - Core Data - NSColor stops working as transformable attribute [duplicate]

I store colours in my binary Core Data store using a transformable attribute, specifying the class of the attribute as UIColor like so:
#import "CoreDataEntity+CoreDataClass.h"
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
#interface CoreDataEntity (CoreDataProperties)
+ (NSFetchRequest<CoreDataEntity *> *)fetchRequest;
#property (nullable, nonatomic, retain) UIColor *transformable;
#property (nullable, nonatomic, copy) NSString *string;
#end
NS_ASSUME_NONNULL_END
In the iOS 11 Beta this has stopped working with an error like this :
NSUnderlyingException=value for key 'NS.objects' was of unexpected class 'UIColor'. Allowed classes are '{(\n NSDecimalNumber,\n NSData,\n NSUUID,\n NSNumber,\n NSDate,\n NSArray,\n NSOrderedSet,\n NSDictionaryMapNode,\n NSString,\n NSSet,\n NSDictionary,\n NSURL,\n NSNull\n)}'.}";
NSUnderlyingException = "Can't read binary data from file";
}
I managed to replicate the specific problem in an XCode project on GitHub (Must be run with the XCode Beta twice to get the error).
In the demo project the store type is controlled by NSPersistentStoreDescription and setting it to NSBinaryStoreType, which I do in the AppDelegate in the exanple project, and I add objects in application didFinishLaunchingWithOptions, otherwise it's the standard template from an iOS11 app with core data. Plus a small datamodel and classes.
If you run the project twice, the first time it creates the datastore and everything is fine. The second time, the datastore tries to open and crashes the app. This problem only seems to be related to binary datastores from what I can tell, if I use an SQL backed datastore it works. However, my app is in the wild and uses binary.
I've reported it to Apple as a bug and sought help on the developer forums, but Apple has not acknowledged the bug and no help was coming.
I'm getting a bit worried as the iOS11 release date draws nearer and I have no solution, my app just won't work in iOS11.
I've tried changing the property to NSData and seeing if it was possible to just unarchive the data, but it seems it's still stored internally as a UIColor somehow and the database just won't open.
Can anyone see a workaround? I have the app in the wild, and possibly pushing out an update to convert the datastores before iOS11 could work for some, but that isn't going to guarantee all users get the fix and they could lose their data.
EDIT 1:
Radar number : 33895450
EDIT 2:
It just occured to me that this applies to any transformable attribute in core data, the values supported in the error message are just the default property types.
EDIT 3:
Just out of curiosity I filled out all the fields for the transformable attribute (it was never required before).
I added "NSKeyedUnarchiveFromData" to value transformer name of the core data entity, it should be the default, but you never know. No effect. It must be using the value transformer anyway to know that it's a UIColor.
I filled in the custom class field to be UIColor, no effect.
Edit 5 : I noticed earlier that UIColor now supports NSSecureCoding, should security somehow be the issue somehow overlooked in the other store typed.
Edit : Now that iOS is released, i’ve used one of my TSIs to further escalate this. Do i get them back if i have to use one to get them to fix their software?
Edit : Apple got back to me on my TSI, they said it’s under investigation, there is no workaround, and to wait on the bug. They refunded my TSI because they couldn’t help.
Edit 8: Same problem on macOS High Sierra, with NSColor instead of UIColor.
Apple still have not given me any feedback on my actual bug report.
Well Apple got back to me, there are new persistentStore options!
The text I got from apple:
/* Allows developers to provide an additional set of classes (which
must implement NSSecureCoding) that should be used while decoding a
binary store. Using this option is preferable to using
NSBinaryStoreInsecureDecodingCompatibilityOption.
*/ COREDATA_EXTERN NSString * const NSBinaryStoreSecureDecodingClasses
API_AVAILABLE(macosx(10.13),ios(11.0),tvos(11.0),watchos(4.0));
/* Indicate that the binary store should be decoded insecurely. This
may be necessary if a store has metadata or transformable properties
containing non-standard classes. If possible, developers should use
the NSBinaryStoreSecureDecodingClasses option to specify the contained
classes, allowing the binary store to to be securely decoded.
Applications linked before the availability date will default to using
this option.
*/ COREDATA_EXTERN NSString * const NSBinaryStoreInsecureDecodingCompatibilityOption
API_AVAILABLE(macosx(10.13),ios(11.0),tvos(11.0),watchos(4.0));
It's not immediately clear, but basically you have to supply an NSSet of classes you use as transformable attributes that comply with NSSecureCoding as an option when opening your persistent store.
An example for mine using the UIColor :
NSError *localError;
NSDictionary *options;
if (#available(iOS 11.0, *)) {
options = #{
NSMigratePersistentStoresAutomaticallyOption : #YES,
NSInferMappingModelAutomaticallyOption : #YES,
NSBinaryStoreSecureDecodingClasses : [NSSet setWithObjects:[UIColor class], nil]
};
} else {
// Fallback on earlier versions
options = #{
NSMigratePersistentStoresAutomaticallyOption : #YES,
NSInferMappingModelAutomaticallyOption : #YES,
};
}
NSPersistentStore *newStore = [self.psc addPersistentStoreWithType:NSBinaryStoreType configuration:#"iOS" URL:psURL options:options error:&localError];
EDIT: Adding a solution for the newer way to open core data persistent stores using NSPersistentStoreDescription. This code is based on the current core data template.
- (NSPersistentContainer *)persistentContainer {
// The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
#synchronized (self) {
if (_persistentContainer == nil) {
NSURL *defaultURL = [NSPersistentContainer defaultDirectoryURL];
defaultURL = [defaultURL URLByAppendingPathComponent:#"CoreDataTransformableAttribBug.binary"];
_persistentContainer = [[NSPersistentContainer alloc] initWithName:#"CoreDataTransformableAttribBug"];
NSPersistentStoreDescription *desc = [NSPersistentStoreDescription persistentStoreDescriptionWithURL:defaultURL];
desc.type = NSBinaryStoreType;
if (#available(iOS 11.0, *)) {
[desc setOption:[NSSet setWithObjects:[UIColor class], nil] forKey:NSBinaryStoreSecureDecodingClasses];
}
_persistentContainer.persistentStoreDescriptions = #[desc];
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
if (error != nil) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
NSLog(#"Unresolved error %#, %#", error, error.userInfo);
abort();
} else {
NSLog(#"Description = %#", storeDescription);
}
}];
}
}
return _persistentContainer;
}
I also updated my gitHub project with the fix in a branch
George did all the hard work. I only applied it to Swift. Here is my solution. I put it into my NSPersistentDocument descendant.
override func configurePersistentStoreCoordinator(for url: URL, ofType fileType: String, modelConfiguration configuration: String?, storeOptions: [String : Any]? = nil) throws {
var options = storeOptions != nil ? storeOptions! : [String:Any]()
if #available(OSX 10.13, *) {
options[NSBinaryStoreSecureDecodingClasses] = NSSet(object: NSColor.self)
}
options[NSMigratePersistentStoresAutomaticallyOption] = true
options[NSInferMappingModelAutomaticallyOption] = true
try super.configurePersistentStoreCoordinator(for: url, ofType: fileType, modelConfiguration: configuration, storeOptions: options)
}
Now I can read my files again. Thanks George!

GPUImage terminates due to [AVAssetWriter startWriting] Cannot call method when status is 3'

I am having an issue running GPUImage. I have modified SimpleVideoFileFilter program(replaced the filter with a chromakeyfilter) and am using my own video. My program is terminating due to the following error:
[AVAssetWriter startWriting] Cannot call method when status is 3'
I have gone through the forums but not sure why the moviewriter is closing and then someone is writing to it.
I am using iPhone4 running iOS 7.0
Any clues are greatly appreciated. Thanks much!
Check whether your destination file exists already. If it does, remove it.
I was trying to add the file to a directory which did not exist. Example : /Videos/Video.mov , leaving it just /Video.mov worked.
Ok, I have a few ideas for you.
When you say "it just shows a frame and never plays the video" we have a good indication that your entire processing pipeline from start to finish is functional exactly once, then stops working.
That tells us that you are stringing things together correctly, but some of the components don't exist longer than a single frame buffer cycle, and subsequently the whole process stops.
it looks like filter and movieWriter are scoped to the class (I'm assuming they're not properties from the lack of an underscore, _filter and _movieWriter). So they will live on after this method has finished (correct me if I'm wrong...)
I think where you are encountering trouble is your (GPUImageView*)displayView
This should probably be declared as a class property (although it could work as just a variable) and then instantiated through the nib or the viewDidLoad method of the view controller.
As you have it now, this line: GPUImageView* filterView = (GPUImageView*)displayView; is making an assignment for filterView which is not used (and therefore unnecessary). It's not clear if displayView really is an instance of GPUImageView or if it will still be in existence when the current method finishes. (in fact you say it "is a UIView that I have programmatically created")
displayView will have to be a subclass of GPUImageView for this whole thing to work, and it will have to be scoped to the class, and not the method.
Declare it like this:
#property (strong, nonatomic)GPUImageView* displayView;
and then instantiate it and add it to your view hierarchy from within viewDidLoad
movieFile1 = [[GPUImageMovie alloc] initWithURL:movieFileURL1];
movieFile2 = [[GPUImageMovie alloc] initWithURL:movieFileURL2];
movieFile2.runBenchmark = YES;
movieFile2.playAtActualSpeed = NO;
filter = [[GPUImageChromaKeyBlendFilter alloc] init];
[(GPUImageChromaKeyBlendFilter *)filter setColorToReplaceRed:0.0 green:1.0 blue:0.0];
[(GPUImageChromaKeyBlendFilter *)filter setThresholdSensitivity:0.4];
GPUImageView *filterView = (GPUImageView*)displayView;
[filter addTarget:displayView];
[movieFile1 addTarget:filter];
[movieFile2 addTarget:filter];
NSString *pathToMovie = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/Movie.m4v"];
unlink([pathToMovie UTF8String]);
NSURL *movieURL = [NSURL fileURLWithPath:pathToMovie];
movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL size:CGSizeMake(1920.0, 1280.0)];
[filter addTarget:movieWriter];
movieWriter.shouldPassthroughAudio = YES;
movieFile1.audioEncodingTarget = movieWriter;
[movieFile1 enableSynchronizedEncodingUsingMovieWriter:movieWriter];
[movieWriter startRecording];
[movieFile1 startProcessing];
[movieFile2 startProcessing];
[movieWriter setCompletionBlock:^{
[filter removeTarget:movieWriter];
[movieWriter finishRecording];
}];
if (outputPath) {
finalURL = [[stongObj tempFileURL] copy];
DebugLog(#"Start Filter Processing :%#",finalURL);
DebugLog(#"movieUrl :%#",movieUrl);
// [CSUtils removeChuckFilePaths:#[outputPath]];
//Create Image Movie Object
_movieFile = [[GPUImageMovie alloc] initWithURL:outputPath];
//_movieFile = [[GPUImageMovie alloc] initWithURL:[[NSBundle mainBundle] URLForResource:#"videoviewdemo" withExtension:#"mp4"]];
_movieFile.runBenchmark = NO;
_movieFile.playAtActualSpeed = YES;
_movieFile.delegate = self;
//Movie Writer Object
_movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:finalURL size:CGSizeMake([UIScreen mainScreen].bounds.size.height,[UIScreen mainScreen].bounds.size.height)];
//_movieWriter.delegate = self;
//Create Selecetive GPU Image Filter
[stongObj setGpuOutputFilter:selectedVideoFilterType];
//Create Group Filter
groupFilter = [[GPUImageFilterGroup alloc] init];
[groupFilter addTarget:imageOutputFilter];
// Only Single Filter is implemented.
//Apply Initial and Terminal Filter
[(GPUImageFilterGroup *)groupFilter setInitialFilters:[NSArray arrayWithObject:imageOutputFilter]];
[(GPUImageFilterGroup *)groupFilter setTerminalFilter:imageOutputFilter];
//_movieWriter -> groupFilter ->_movieFile
[_movieFile addTarget:groupFilter];
[groupFilter addTarget:_movieWriter];
_movieWriter.shouldPassthroughAudio = YES;
_movieFile.audioEncodingTarget = _movieWriter;
[_movieFile enableSynchronizedEncodingUsingMovieWriter:_movieWriter];
//Start Recording
[_movieWriter startRecording];
//Start Processing
[_movieFile startProcessing];
__weak typeof(self) weekSelf=self;
[_movieWriter setCompletionBlock:^{
__strong typeof(self) stongSelf=weekSelf;
DebugLog(#"Movie Write Completed");
//Finish Recording.
[stongSelf.movieWriter finishRecording];
//Release all object
// [self releaseAllObject];
//remove movieUrl,audioUrl,outputPath
[CSUtils removeChuckFiles:#[movieUrl,audioUrl,outputPath]];
}];
[_movieFile startProcessing]; app get crash in iOS 8 on this line but working fine on iOS 7
#Seasia Creative ,I have no enough reputation to add a comment by that list,I create a new list to answer U.
I check the output URL,console log "/var~~~~/tmpmerge.mp4",so i realize that ,i miss a "/" --->"/var~~~~/tmp/merge.mp4".
If the url is no correct, project runs into the same error.
hope to help some.

RestKit / Core Data: Remotely deleted entities get not removed from Core Data

Why do remotely deleted entities not removed from Core Data and the datastore? Setting a breakpoint at the beginning of
- (void)deleteCachedObjectsMissingFromResult:(RKObjectMappingResult *)result
in RKManagedObjectLoader shows up that the variable result does not contain anything.
I could fix that problem by implementing this feature in the RestKit delegate - (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects but that is kind of unclean code in my point of view. RestKit / Core Data should do that by itself?! Anyway, following implementation would solve the problem:
- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects
{
NSArray *allReservations = [Reservation findAll];
for(Reservation *reservationRecord in allReservations) {
if(![objects containsObject:reservationRecord]) {
[[[[RKObjectManager sharedManager] objectStore] managedObjectContextForCurrentThread] deleteObject:reservationRecord];
}
}
}
any ideas to solve that problem without the help of didLoadObjects? Adding / updating existing entities works properly.
RestKit will only delete the entries in the NSManagedObjectContext. Your method only edits the objects in the NSManagedObjectContext but never saves them to the objectStore. Make sure to save the changes to the ObjectStore after the adding/editing/deleting has been finished.
- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects
{
NSArray *allReservations = [Reservation findAll];
// Deleting each item in NSManagedObjectContext
for(Reservation *reservationRecord in allReservations) {
if(![objects containsObject:reservationRecord]) {
[[[RKObjectManager sharedManager] objectStore] managedObjectContextForCurrentThread] deleteObject:reservationRecord];
}
}
// Changes only exist in NSManagedObjectContext, delete them in the ObjectStore
NSError *error = nil;
if (![[[RKObjectManager sharedManager] objectStore] managedObjectContextForCurrentThread] save:&error])
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}

Hard CoreData + iCloud scenario

i'm having a very hard issue to solve. I've got this scenario:
My app uses CoreData to storing objects, I want to implement iCloud sync between devices... and my app requires an initial populated database.
The first time I launch my app, it's going to populate my database on the cloud and marks to YES some db'fields as "databaseInstalled". These fields are synced in the cloud too.
Now when another device launch the app for the first time, I was hoping to retrieve the field "databaseInstalled" to check whether inject or not some data but it's wrong...
If databaseInstalled is false, we inject data, if databaseInstalled it's true, we wait for iCloud sync.
The problem is that I retrieve the persistentStoreCoordinator asynchronically because of I don't want to block the app that is waiting to download data from iCloud...
So how can I know a priori if i need to populate the database or it has been filled on another device and I've just to download from iCloud the populated one?
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if((__persistentStoreCoordinator != nil)) {
return __persistentStoreCoordinator;
}
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
NSPersistentStoreCoordinator *psc = __persistentStoreCoordinator;
// Set up iCloud in another thread:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// ** Note: if you adapt this code for your own use, you MUST change this variable:
NSString *iCloudEnabledAppID = #"this is a secret!";
// ** Note: if you adapt this code for your own use, you should change this variable:
NSString *dataFileName = #"you do not have to know.sqlite";
// ** Note: For basic usage you shouldn't need to change anything else
NSString *iCloudDataDirectoryName = #"Data.nosync";
NSString *iCloudLogsDirectoryName = #"Logs";
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *localStore = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:dataFileName];
NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil];
if (iCloud) {
NSLog(#"iCloud is working");
NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]];
NSLog(#"iCloudEnabledAppID = %#",iCloudEnabledAppID);
NSLog(#"dataFileName = %#", dataFileName);
NSLog(#"iCloudDataDirectoryName = %#", iCloudDataDirectoryName);
NSLog(#"iCloudLogsDirectoryName = %#", iCloudLogsDirectoryName);
NSLog(#"iCloud = %#", iCloud);
NSLog(#"iCloudLogsPath = %#", iCloudLogsPath);
// da rimuovere
//[fileManager removeItemAtURL:iCloudLogsPath error:nil];
#warning to remove
if([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) {
NSError *fileSystemError;
[fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]
withIntermediateDirectories:YES
attributes:nil
error:&fileSystemError];
if(fileSystemError != nil) {
NSLog(#"Error creating database directory %#", fileSystemError);
}
}
NSString *iCloudData = [[[iCloud path]
stringByAppendingPathComponent:iCloudDataDirectoryName]
stringByAppendingPathComponent:dataFileName];
//[fileManager removeItemAtPath:iCloudData error:nil];
#warning to remove
NSLog(#"iCloudData = %#", iCloudData);
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[options setObject:iCloudEnabledAppID forKey:NSPersistentStoreUbiquitousContentNameKey];
[options setObject:iCloudLogsPath forKey:NSPersistentStoreUbiquitousContentURLKey];
[psc lock];
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:[NSURL fileURLWithPath:iCloudData]
options:options
error:nil];
[psc unlock];
}
else {
NSLog(#"iCloud is NOT working - using a local store");
NSLog(#"Local store: %#", localStore.path);
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[psc lock];
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:localStore
options:options
error:nil];
[psc unlock];
}
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"iCloud routine completed.");
Setup *install = [[Setup alloc] init];
if([install shouldMigrate]) {
HUD = [[MBProgressHUD alloc] initWithView:self.window.rootViewController.view];
HUD.delegate = self;
HUD.labelText = NSLocalizedString(#"Sincronizzazione del database", nil);
[self.window.rootViewController.view addSubview:HUD];
[HUD showWhileExecuting:#selector(installDatabase) onTarget:install withObject:nil animated:YES];
}
else {
[[NSNotificationCenter defaultCenter] postNotificationName:#"setupCompleted" object:self];
}
//[[NSNotificationCenter defaultCenter] postNotificationName:#"icloudCompleted" object:self userInfo:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"setupCompleted" object:self];
});
});
return __persistentStoreCoordinator;
}
You can't know whether or not there's going to be data available in iCloud until you finish syncing with iCloud. That means that you've got two options:
Make the user wait until the sync is done.
Start up with your default database and merge changes from iCloud when possible.
With iCloud, you need some strategy for resolving conflicts between local data and cloud data because you have to deal with the fact that users might change data on more than one device at the same time. Once you have that in place, it seems pretty clear that the second option above is the better one: users get to start using your app right away, and data from the cloud is merged when it's available.
I had exactly same problem.
Check out my question & my answer to it iCloud + CoreData - how to avoid pre-filled data duplication?
Actually it doesn't work 100% ok. If you dare to try it I can explain you how you might make it work 100% correctly (I haven't tried yet, though).
Taking into account that you have a lot of data to pre-populate my solution might now work out for you.
There is no way to determine whether a data store is being opened for the first time. At least not on iCloud Core Data store. Think of it, iCloud should also work off-line – that is, all changes should be buffered when the user is disconnected from the Internet and then uploaded when the connection is restored. There is no way to check whether a data store was initialized without potentially making the user wait for a few minutes (or even indefinitely if the device is off-line) to ask iCloud's copy of the data sore.
To solve this, you'll need to follow these four simple guidelines:
Have a way to de-duplicate pre-populated records.
Have a way to identify pre-populated records and differentiate it from user-entered ones.
Run the de-duplication process every time new transaction records came in from iCloud.
Only seed data records once per device/account combination.
You can read more details here: http://cutecoder.org/programming/seeding-icloud-core-data/

How implement splitview for iphone os 4.2?

I have use the custom splitview in the my application.
custom splitview .h file
#interface CustomUISplitViewController :UISplitViewController {
BOOL keepMasterInPortraitMode;
BOOL keepMasterInPortraitMode1;
}
and .m file is
-(void) viewWillAppear:(BOOL)animated {
keepMasterInPortraitMode1=keepMasterInPortraitMode;
if(keepMasterInPortraitMode1 == NO) {
if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft || self.interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
UIViewController* master = [self.viewControllers objectAtIndex:0];
UIViewController* detail = [self.viewControllers objectAtIndex:1];
[self setupPortraitMode:master detail:detail];
}
}
if (self.interfaceOrientation == UIInterfaceOrientationPortrait || self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
UIViewController* master = [self.viewControllers objectAtIndex:0];
UIViewController* detail = [self.viewControllers objectAtIndex:1];
[self setupPortraitMode:master detail:detail];
}
}
}
- (void)setupPortraitMode:(UIViewController*)master detail:(UIViewController*)detail {
//adjust master view
CGRect f = master.view.frame;
f.size.width = 220;
f.size.height = 1024;
f.origin.x = 0;
f.origin.y =0;
[master.view setFrame:f];
//adjust detail view
f = detail.view.frame;
f.size.width = 548;
f.size.height = 1024;
f.origin.x = 221;
f.origin.y = 0;
[detail.view setFrame:f];
}
This works correctly under iOS4.0 but under 4.2 I see only one view when the app runs. What could change between OS versions?
I was having the same issue and I believe this to be an Apple bug (I filed it a month ago with no response from them.) For me, it was specifically the "detail" view that was blank when the app started at orientation UIInterfaceOrientationLandscapeRight (3). It would look like this: http://d.pr/cGcU. This would occur when I restricted one of the two view controllers (say, the RootViewController) to landscape-only:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
With this in place, the following would occur during the detail view's initialization:
2010-11-15 20:17:47.792 MultipleDetailViews[96250:207] firstDetailViewController willAnimateRotationToInterfaceOrientation: 3 (landscape)
2010-11-15 20:17:47.792 MultipleDetailViews[96250:207] self.view.hidden is: 0
2010-11-15 20:17:47.799 MultipleDetailViews[96250:207] rotating...
2010-11-15 20:17:47.848 MultipleDetailViews[96250:207] firstDetailViewController didRotateFromInterfaceOrientation
2010-11-15 20:17:47.849 MultipleDetailViews[96250:207] self.view.hidden is: 1
For some reason the detail view would mysteriously become hidden during rotation to orientation 3. Until Apple fixes this bug (it doesn't occur in 3.2), my workaround is currently to override the following method in the detail view controller, re-displaying the view after rotation has completed:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
self.view.hidden = NO;
}
EDIT: If your detail view isn't a direct subview of splitViewController.view (e.g. you are using a UINavigationController), you will need to set hidden on the topmost view on the detail side within the UISplitViewController:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
// Make sure you set splitViewController via an outlet or get it via your AppDelegate
for (UIView *splitViewChild in splitViewController.view.subviews)
splitViewChild.hidden = NO;
}
I have had the exact same problem with my applications. I had used the same Subclassing technique to have the Master and Detail visible in both Portrait and Landscape modes. Worked great until 4.2 which, unfortunately I didn't test for when the Beta releases were available.
I recommend trying the excellent MGSplitViewController (http://mattgemmell.com/2010/07/31/mgsplitviewcontroller-for-ipad). It is an open-source implementation of the UISplitViewController. It's only drawback is that it isn't quite as easy to use in Interface Builder, but it includes a sample project. Visually it is identical to UISplitViewController, but adds support for several extras such as dragging the split position at runtime.
Just implement it exactly as your UISplitViewController but add the following line somewhere:
[splitViewController setShowsMasterInPortrait:YES];
This is very similar to the Private API that Apple prohibits using with their version.
//[splitViewController setHidesMasterViewInPortrait:NO]; // Naughty, Naughty, Not allowed by the Apple police

Resources