In my app if I tap one button I need to display all the phone contacts like whatsapp... How to acheive this with AddressBook framework? Or can we use any other frameworks to display all the device contacts...
We can fetch the contact using the contact framework: following the step->
Add the contact.framework and contactUI.framework in your app bundle.
Add the two file in your .h file:
#import Contacts/Contacts.h
#import ContactsUI/ContactsUI.h
Add the flowing code
-(void)loadContactList
{
#try {
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
if( status == CNAuthorizationStatusDenied || status == CNAuthorizationStatusRestricted)
{
NSLog(#"access denied");
}
else
{
//Create repository objects contacts
CNContactStore *contactStore = [[CNContactStore alloc] init];
//Select the contact you want to import the key attribute ( https://developer.apple.com/library/watchos/documentation/Contacts/Reference/CNContact_Class/index.html#//apple_ref/doc/constant_group/Metadata_Keys )
NSArray *keys = [[NSArray alloc]initWithObjects:CNContactIdentifierKey, CNContactEmailAddressesKey, CNContactBirthdayKey, CNContactImageDataKey, CNContactPhoneNumbersKey,CNContactViewController.descriptorForRequiredKeys,nil];
// Create a request object
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:keys];
request.predicate = nil;
[contactStore enumerateContactsWithFetchRequest:request
error:nil
usingBlock:^(CNContact* __nonnull contact, BOOL* __nonnull stop)
{
// Contact one each function block is executed whenever you get
NSString *phoneNumber = #"";
if( contact.phoneNumbers)
phoneNumber = [[[contact.phoneNumbers firstObject] value] stringValue];
NSLog(#"phoneNumber = %#", phoneNumber);
NSLog(#"givenName = %#", contact.givenName);
NSLog(#"familyName = %#", contact.familyName);
NSLog(#"email = %#", contact.emailAddresses);
[contactList addObject:contact];
}];
}
} #catch (NSException *exception) {
NSLog(#"Exception:%#",exception.reason);
}
}
Call this method in view did load or view did appear.
I have run into an issue on iOS 8 with the Assets Library framework that appears to be a bug in iOS 8. If I create an album called 'MyMedia' and then delete it, then when I try to create the album again, this chunk of code below returns 'nil' indicating that the album 'MyMedia' exists even though it does not because I deleted it using the 'Photos' app.
__block ALAssetsGroup *myGroup = nil;
__block BOOL addAssetDone = false;
NSString *albumName = #"MyMedia";
[assetsLib addAssetsGroupAlbumWithName:albumName
resultBlock:^(ALAssetsGroup *group) {
myGroup = group;
addAssetDone = true;
} failureBlock:^(NSError *error) {
NSLog( #"failed to create album: %#", albumName);
addAssetDone = true;
}];
while (!addAssetDone) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.05f]];
}
return myGroup; // returns nil if group has previously been created and then deleted
This same method works when creating a brand new album 'MyMedia2.' Has anyone else experienced this issue and know of a workaround or solution? Is the only solution to move to the new 'Photos' framework or am I doing something incorrect here? Note that this code always works on iOS7.X
Actually the steps to reproduce this problem are as follows ->
1. Uninstall your app that takes photos and saves them to a custom album
2. Under iOS Photos delete the custom album that has saved photos in it
3. Install your app
4. If you take pictures or record videos with the app it does not create them or store them. If you look under iOS Photos albums the custom album one does not exist and none of the pictures/videos taken with the app exist.
My previous answer was incorrect. I had not really tested it out. I did finally figure out what had to be done and it was difficult but I got it to work. This is what I had to do to get my app to run on both iOS 7.x.X and iOS 8.X.x and create a custom album that had been previously deleted by the app -->
I wrote two chunks of code: one that uses the Photos framework on iOS 8.x.x and one that uses the AssetsLibrary framework on iOS 7.x.x
Sp the app could run on both iOS versions, I linked the app to the Photos framework but then changed it from required to optional so it would not be loaded on iOS 7.x.x
Because the Photos framework code could not be called directly at runtime on iOS 7.x.x, I had to change it so it loaded the classes, functions (and blocks!) dynamically at runtime
Here is the code chunk that works when running on an iPhone. This should work in the simulator too -->
// PHPhotoLibrary_class will only be non-nil on iOS 8.x.x
Class PHPhotoLibrary_class = NSClassFromString(#"PHPhotoLibrary");
if (PHPhotoLibrary_class) {
/**
*
iOS 8..x. . code that has to be called dynamically at runtime and will not link on iOS 7.x.x ...
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:title];
} completionHandler:^(BOOL success, NSError *error) {
if (!success) {
NSLog(#"Error creating album: %#", error);
}
}];
*/
// dynamic runtime code for code chunk listed above
id sharedPhotoLibrary = [PHPhotoLibrary_class performSelector:NSSelectorFromString(#"sharedPhotoLibrary")];
SEL performChanges = NSSelectorFromString(#"performChanges:completionHandler:");
NSMethodSignature *methodSig = [sharedPhotoLibrary methodSignatureForSelector:performChanges];
NSInvocation* inv = [NSInvocation invocationWithMethodSignature:methodSig];
[inv setTarget:sharedPhotoLibrary];
[inv setSelector:performChanges];
void(^firstBlock)() = ^void() {
Class PHAssetCollectionChangeRequest_class = NSClassFromString(#"PHAssetCollectionChangeRequest");
SEL creationRequestForAssetCollectionWithTitle = NSSelectorFromString(#"creationRequestForAssetCollectionWithTitle:");
[PHAssetCollectionChangeRequest_class performSelector:creationRequestForAssetCollectionWithTitle withObject:albumName];
};
void (^secondBlock)(BOOL success, NSError *error) = ^void(BOOL success, NSError *error) {
if (success) {
[assetsLib enumerateGroupsWithTypes:ALAssetsGroupAlbum usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if (group) {
NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
if ([albumName isEqualToString:name]) {
groupFound = true;
handler(group, nil);
}
}
} failureBlock:^(NSError *error) {
handler(nil, error);
}];
}
if (error) {
NSLog(#"Error creating album: %#", error);
handler(nil, error);
}
};
// Set the success and failure blocks.
[inv setArgument:&firstBlock atIndex:2];
[inv setArgument:&secondBlock atIndex:3];
[inv invoke];
}
else {
// code that always creates an album on iOS 7.x.x but fails
// in certain situations such as if album has been deleted
// previously on iOS 8...x. .
[assetsLib addAssetsGroupAlbumWithName:albumName
resultBlock:^(ALAssetsGroup *group) {
handler(group, nil);
} failureBlock:^(NSError *error) {
NSLog( #"Failed to create album: %#", albumName);
handler(nil, error);
}];
}
Using Adam's answer, and Marin Todorov's Category on ALAssetsLibrary, ALAssetsLibrary+CustomPhotoAlbum to create photo Albums, and place photos in them, this code below replaces the main workHorse in that Category, it works on both iOS7 devices and iOS 8.1 devices for those who need to have both.
it gives two warnings about performSelector on unknown class though, any improvements are appreciated:
(it will not copy a photo from a shared album that you did not create and will fail with message, any enhancements there also would be good)
1) add the "Photos" Frameworks, set to "optional"
2) include the import line #import < Photos/PHPhotoLibrary.h >
//----------------------------------------------------------------------------------------
- (void)addAssetURL:(NSURL *)assetURL
toAlbum:(NSString *)albumName
completion:(ALAssetsLibraryWriteImageCompletionBlock)completion
failure:(ALAssetsLibraryAccessFailureBlock)failure
{
NSLog();
__block BOOL albumWasFound = NO;
//-----------------------------------------
ALAssetsLibraryGroupsEnumerationResultsBlock enumerationBlock;
enumerationBlock = ^(ALAssetsGroup *group, BOOL *stop)
{
NSLog(#" ALAssetsLibraryGroupsEnumerationResultsBlock");
// Compare the names of the albums
if ([albumName compare:[group valueForProperty:ALAssetsGroupPropertyName]] == NSOrderedSame)
{
NSLog(#"--------------Target album is found");
// Target album is found
albumWasFound = YES;
// Get a hold of the photo's asset instance
// If the user denies access to the application, or if no application is allowed to
// access the data, the failure block is called.
ALAssetsLibraryAssetForURLResultBlock assetForURLResultBlock =
[self _assetForURLResultBlockWithGroup:group
assetURL:assetURL
completion:completion
failure:failure];
[self assetForURL:assetURL
resultBlock:assetForURLResultBlock
failureBlock:failure];
// Album was found, bail out of the method
*stop = YES;
}
if (group == nil && albumWasFound == NO)
{
NSLog(#"--------------Target album does not exist");
// Photo albums are over, target album does not exist, thus create it
// Since you use the assets library inside the block,
// ARC will complain on compile time that there’s a retain cycle.
// When you have this – you just make a weak copy of your object.
ALAssetsLibrary * __weak weakSelf = self;
// If iOS version is lower than 5.0, throw a warning message
if (! [self respondsToSelector:#selector(addAssetsGroupAlbumWithName:resultBlock:failureBlock:)])
{
NSLog(#"--------------Target album does not exist and does not respond to addAssetsGroupAlbumWithName");
} else {
NSLog(#"--------------Target album does not exist addAssetsGroupAlbumWithName");
// ----------- PHPhotoLibrary_class will only be non-nil on iOS 8.x.x -----------
Class PHPhotoLibrary_class = NSClassFromString(#"PHPhotoLibrary");
NSLog(#"PHPhotoLibrary_class %# ", PHPhotoLibrary_class);
if (PHPhotoLibrary_class)
{
NSLog(#"iOS8");
// --------- dynamic runtime code -----------
id sharedPhotoLibrary = [PHPhotoLibrary_class performSelector:NSSelectorFromString(#"sharedPhotoLibrary")];
NSLog(#"sharedPhotoLibrary %# ", sharedPhotoLibrary);
SEL performChanges = NSSelectorFromString(#"performChanges:completionHandler:");
NSMethodSignature *methodSig = [sharedPhotoLibrary methodSignatureForSelector:performChanges];
NSInvocation* inv = [NSInvocation invocationWithMethodSignature:methodSig];
[inv setTarget:sharedPhotoLibrary];
[inv setSelector:performChanges];
void(^firstBlock)() = ^void()
{
NSLog(#"firstBlock");
Class PHAssetCollectionChangeRequest_class = NSClassFromString(#"PHAssetCollectionChangeRequest");
SEL creationRequestForAssetCollectionWithTitle = NSSelectorFromString(#"creationRequestForAssetCollectionWithTitle:");
NSLog(#"PHAssetCollectionChangeRequest_class %# ", PHAssetCollectionChangeRequest_class);
[PHAssetCollectionChangeRequest_class performSelector:creationRequestForAssetCollectionWithTitle withObject:albumName];
};
void (^secondBlock)(BOOL success, NSError *error) = ^void(BOOL success, NSError *error)
{
NSLog(#"secondBlock");
if (success)
{
NSLog(#"success");
[self enumerateGroupsWithTypes:ALAssetsGroupAlbum usingBlock:^(ALAssetsGroup *group, BOOL *fullStop)
{
if (group)
{
NSLog(#"group %# ", group);
NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
if ([albumName isEqualToString:name])
{
NSLog(#"[albumName isEqualToString:name] %# ", name);
ALAssetsLibraryAssetForURLResultBlock assetForURLResultBlock =
[self _assetForURLResultBlockWithGroup:group
assetURL:assetURL
completion:completion
failure:failure];
[self assetForURL:assetURL
resultBlock:assetForURLResultBlock
failureBlock:failure];
*fullStop = YES;
}
}
} failureBlock:failure];
}
if (error)
{
NSLog(#"Error creating album: %#", error);
}
};
// Set the success and failure blocks.
[inv setArgument:&firstBlock atIndex:2];
[inv setArgument:&secondBlock atIndex:3];
[inv invoke];
} else {
NSLog(#"iOS7");
[self addAssetsGroupAlbumWithName:albumName resultBlock:^(ALAssetsGroup *createdGroup)
{
// Get the photo's instance, add the photo to the newly created album
ALAssetsLibraryAssetForURLResultBlock assetForURLResultBlock =
[weakSelf _assetForURLResultBlockWithGroup:createdGroup
assetURL:assetURL
completion:completion
failure:failure];
[weakSelf assetForURL:assetURL
resultBlock:assetForURLResultBlock
failureBlock:failure];
}
failureBlock:failure];
}
}
// Should be the last iteration anyway, but just in case
*stop = YES;
}
};
// Search all photo albums in the library
[self enumerateGroupsWithTypes:ALAssetsGroupAlbum
usingBlock:enumerationBlock
failureBlock:failure];
}
You can try My below Method for Create Album for iOS 7 and iOS 8
#define PHOTO_ALBUM_NAME #"AlbumName Videos"
#pragma mark - Create Album
-(void)createAlbum{
// PHPhotoLibrary_class will only be non-nil on iOS 8.x.x
Class PHPhotoLibrary_class = NSClassFromString(#"PHPhotoLibrary");
if (PHPhotoLibrary_class) {
// iOS 8..x. . code that has to be called dynamically at runtime and will not link on iOS 7.x.x ...
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:PHOTO_ALBUM_NAME];
} completionHandler:^(BOOL success, NSError *error) {
if (!success) {
NSLog(#"Error creating album: %#", error);
}else{
NSLog(#"Created");
}
}];
}else{
[self.library addAssetsGroupAlbumWithName:PHOTO_ALBUM_NAME resultBlock:^(ALAssetsGroup *group) {
NSLog(#"adding album:'Compressed Videos', success: %s", group.editable ? "YES" : "NO");
if (group.editable == NO) {
}
} failureBlock:^(NSError *error) {
NSLog(#"error adding album");
}];
}}
Just wanted to update everyone I should have updated sooner but I got kind of swamped with work. This issue is/was an issue with iOS 8 but has been fixed with iOS 8.0.2 so all you need to do to fix it is update your iOS to iOS 8.0.2
I used the below code to check whether a specific album exists, and if it does not exist, create it and add a couple of images to it. After creating an Asset from a UIImage, I use its placeholder to add it to the album without leaving the block.
//Will enter only in iOS 8+
Class PHPhotoLibrary_class = NSClassFromString(#"PHPhotoLibrary");
if (PHPhotoLibrary_class)
{
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^
{
//Checks for App Photo Album and creates it if it doesn't exist
PHFetchOptions *fetchOptions = [PHFetchOptions new];
fetchOptions.predicate = [NSPredicate predicateWithFormat:#"title == %#", kAppAlbumName];
PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:fetchOptions];
if (fetchResult.count == 0)
{
//Create Album
PHAssetCollectionChangeRequest *albumRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:kAppAlbumName];
//Add default photos to it
NSMutableArray *photoAssets = [[NSMutableArray alloc] init];
for (UIImage *image in albumDefaultImages)
{
PHAssetChangeRequest *imageRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
[photoAssets addObject:imageRequest.placeholderForCreatedAsset];
}
[albumRequest addAssets:photoAssets];
}
}
completionHandler:^(BOOL success, NSError *error)
{
NSLog(#"Log here...");
}];
}
As none of the above suggestions helped me, this is how I went about solving the issues with saving assets (photos) to a custom album name.
This code: "fetchCollectionResult.count==0" specifically handles the situation when you have deleted your custom album once and trying to save to it again, as I suppose fetchCollectionResult might stop being 'nil'.
You can easily change this to support saving of videos/movies too.
This code is for iOS 8 only!
You must make sure not to call it if the device is running on earlier versions!
#define PHOTO_ALBUM_NAME #"MyPhotoAlbum"
NSString* existingAlbumIdentifier = nil;
-(void)saveAssetToAlbum:(UIImage*)myPhoto
{
PHPhotoLibrary* photoLib = [PHPhotoLibrary sharedPhotoLibrary];
__block NSString* albumIdentifier = existingAlbumIdentifier;
__block PHAssetCollectionChangeRequest* collectionRequest;
[photoLib performChanges:^
{
PHFetchResult* fetchCollectionResult;
if ( albumIdentifier )
fetchCollectionResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:#[albumIdentifier] options:nil];
// Create a new album
if ( !fetchCollectionResult || fetchCollectionResult.count==0 )
{
NSLog(#"Creating a new album.");
collectionRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:PHOTO_ALBUM_NAME];
albumIdentifier = collectionRequest.placeholderForCreatedAssetCollection.localIdentifier;
}
// Use existing album
else
{
NSLog(#"Fetching existing album, of #%d albums found.", fetchCollectionResult.count);
PHAssetCollection* exisitingCollection = fetchCollectionResult.firstObject;
collectionRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:exisitingCollection];
}
NSLog(#"Album local identifier = %#", albumIdentifier);
PHAssetChangeRequest* createAssetRequest;
createAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:myPhoto];
[collectionRequest addAssets:#[createAssetRequest.placeholderForCreatedAsset]];
}
completionHandler:^(BOOL success, NSError *error)
{
if (success)
{
existingAlbumIdentifier = albumIdentifier;
NSLog(#"added image to album:%#", PHOTO_ALBUM_NAME);
}
else
NSLog(#"Error adding image to album: %#", error);
}];
}
I created an entity named House. This entity has two attributes which are street (of type string) and numOfStories (of type integer 32). I was able to successfully save and NSLog data in my AppDelegate.m didFinishLaunchingWithOptions method. However, when I try to make 2 textfields and show the User's input, and make a button to save, the result is SIGABRT.
Here is all the code I'm using in my MainViewController.m:
- (BOOL)createNewHouseWithStreet:(NSString *)paramStreet numOfStories: (NSUInteger)paramNumOfStories
{
BOOL result = NO;
if ([paramStreet length] == 0)
{
NSLog(#"Street name is mandatory");
return NO;
}
House *newHouse = [NSEntityDescription insertNewObjectForEntityForName:#"House" inManagedObjectContext:self.managedObjectContext];
if (newHouse == nil)
{
NSLog(#"Failed to create the new House");
return NO;
}
newHouse.street = paramStreet;
newHouse.numOfStories = #(paramNumOfStories);
NSError *savingError = nil;
if ([self.managedObjectContext save:&savingError])
{
return YES;
}
else
{
NSLog(#"Failed the save the new House. Error = %#", savingError);
}
return result;
}
and below this I have
- (IBAction)save:(id)sender {
[self createNewHouseWithStreet:#"10 WYOMING" numOfStories:2];
[self createNewHouseWithStreet:#"6 WYOMING" numOfStories:3];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"House"];
NSError *requestError = nil;
NSArray *houses = [self.managedObjectContext executeFetchRequest:fetchRequest error:&requestError];
if ([houses count] > 0)
{
NSUInteger counter = 1;
for (House *thisHouse in houses)
{
NSLog(#"House %lu Street Name = %#", (unsigned long)counter, thisHouse.street);
NSLog(#"House %lu number of stories = %ld", (unsigned long)counter, (unsigned long)[thisHouse.numOfStories unsignedIntegerValue]);
counter++;
}
}
else
{
NSLog(#"Could not find any House entities in the context.");
}
}
So what's weird is that this code ends up resulting in sigabrt whenever I tap the save button, but when I put the code from the save method into my AppDelegate.m didFinishLaunchingWithOptions method it works great.
All help is appreciated, thanks.
In my application, I have Category and Sub_Category entities which are having a to-many relation ship between them.
Firstly, when the App runs for the first time the relation attribute(category_subCategory) is working as shown below:
2012-04-11 04:03:39.344 SupplyTrackerApp[27031:12f03] Saved
2012-04-11 04:03:47.423 SupplyTrackerApp[27031:fb03] Category<Category: 0x6ba4e90> (entity: Category; id: 0x6e95620 <x-coredata://00E5784E-D032-41DD-BD60-B85B0BBF8E31/Category/p1> ; data: {
categoryID = 1;
categoryName = Antiques;
"category_SubCategory" = (
"0x6ebb4f0 <x-coredata://00E5784E-D032-41DD-BD60-B85B0BBF8E31/Sub_Category/p1>"
);
catetogoryDescription = "Contains a Sub categories related to Antique pieces";
})
But when I exit the app an restart the application, that relationship does exists. The output looks like this..
2012-04-11 04:05:04.455 SupplyTrackerApp[27038:fb03] In Cell for row at index path
2012-04-11 04:05:05.548 SupplyTrackerApp[27038:fb03] Category<Category: 0x6ecaca0> (entity: Category; id: 0x6eb4ab0 <x-coredata://00E5784E-D032-41DD-BD60-B85B0BBF8E31/Category/p1> ; data: {
categoryID = 1;
categoryName = Antiques;
"category_SubCategory" = "<relationship fault: 0x6ecf0a0 'category_SubCategory'>";
catetogoryDescription = "Contains a Sub categories related to Antique pieces";
})
Here is where I'm calling the create entities..
-(void) loadDataIntoDocument{
NSLog(#"In Load Data");
dispatch_queue_t fetch=dispatch_queue_create("Data Fetcher", NULL);
dispatch_async(fetch, ^{
[Sub_Category createSubCategory:context];
NSError *error;
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}else {
NSLog(#"Saved");
}
});
dispatch_release(fetch);
}
So the Sub_Category+Create Category file has the following code.
+(Sub_Category *) createSubCategory:(NSManagedObjectContext *)context{
Sub_Category *subCategory=nil;
NSFetchRequest *request=[NSFetchRequest fetchRequestWithEntityName:#"Sub_Category"];
request.predicate=[NSPredicate predicateWithFormat:#"subCategoryID=%#", #"11"];
NSSortDescriptor *sortDescriptor=[NSSortDescriptor sortDescriptorWithKey:#"subCategoryName" ascending:YES];
request.sortDescriptors=[NSArray arrayWithObject:sortDescriptor];
NSError *error;
NSArray *matches=[context executeFetchRequest:request error:&error];
if (!matches||[matches count]>1) {
///errorrrrrrrrrr
} else if([matches count]==0) {
subCategory=[NSEntityDescription insertNewObjectForEntityForName:#"Sub_Category" inManagedObjectContext:context];
subCategory.subCategoryID=[NSString stringWithFormat:#"%i", 11];
subCategory.subCategoryName=#"Antiquities";
subCategory.subCategoryDescription=#"Contains several products related to antiquities";
subCategory.subCategory_Category =[Category createCategory:context];
}else {
subCategory=[matches lastObject];
}
return subCategory;
}
And then I'm calling the Category+Create Category file which has the following code.
+(Category *) createCategory:(NSManagedObjectContext *)context{
Category *category=nil;
NSFetchRequest *request=[NSFetchRequest fetchRequestWithEntityName:#"Category"];
request.predicate=[NSPredicate predicateWithFormat:#"categoryID=%#", #"1"];
NSSortDescriptor *sortDescriptor=[NSSortDescriptor sortDescriptorWithKey:#"categoryName" ascending:YES];
request.sortDescriptors=[NSArray arrayWithObject:sortDescriptor];
NSError *error;
NSArray *matches=[context executeFetchRequest:request error:&error];
if (!matches||[matches count]>1) {
///errorrrrrrrrrr
} else if([matches count]==0) {
category=[NSEntityDescription insertNewObjectForEntityForName:#"Category" inManagedObjectContext:context];
category.categoryID=[NSString stringWithFormat:#"%d",1];
category.categoryName=#"Antiques";
category.catetogoryDescription=#"Contains a Sub categories related to Antique pieces";
}else {
category=[matches lastObject];
}
return category;
}
Can anyone help me out regarding this..
I'm stuck on this from few days...
I looks like you're using dispatch_async to do the -save: in the background. This is probably violating the "thread confinement" rules for dealing with an NSManagedObject (in short, they should only be used in the thread they were created on. Same applies to any objects fetched from them).
For more information on how to do concurrency with Core Data, see this WWDC Session.
Try only using your Core Data stack (and any objects you fetch from it) from the main thread.
I'm working With Game Center right now and I have a issue with GC.
When I'm using initWithPlayerIDs:, I don't get any score when loadScoresWithCompletionHandler: callback is called.
GKLeaderboard *leaderBoard = [[[GKLeaderboard alloc] initWithPlayerIDs:[NSArray arrayWithObject:gcPlayerID]] autorelease];
leaderBoard.timeScope = GKLeaderboardTimeScopeAllTime;
leaderBoard.category = #"SomeLeaderboard";
[leaderBoard loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error == nil)
{
// scores is null
// ...
}
But when I'm doing:
GKLeaderboard *leaderBoard = [[[GKLeaderboard alloc] init] autorelease];
leaderBoard.timeScope = GKLeaderboardTimeScopeAllTime;
leaderBoard.category = #"SomeLeaderboard";
[leaderBoard loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error == nil)
{
for (GKScore* score in scores)
if ([score.playerID isEqualToString:gcPlayerID])
{
// Got something here
return;
}
}
It's working.
I'm using the 2nd method at the moment but it will make time to process if there is many score.
Does anyone have the same issue ?
Thanks.
I'm afraid that with the given info I don't have an answer as to why initWithPlayerIDs: is not working. However, I might be able to simplify your filtering for the local player score in the 2nd method. A GKLeaderboard has a property localPlayerScore that is valid only after loadScoresWithCompletionHandler: has completed. localPlayerScore then gives the GKScore for the local player. Your 2nd method would then look like this:
[leaderBoard loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
if (error == nil)
{
GKScore* myScore = leaderboard.localPlayerScore;
}
}
Hope this helps a little.
Try to narrow the type of scores to those you really want to process. For example request the score for the logged in player and for global time scope etc.
I am using something like the following code snippet in my own game and it is fast:
// Load score for player
GKLeaderboard *board = [[GKLeaderboard alloc] initWithPlayerIDs:[NSArray arrayWithObject:myGCPlayerID]];
board.timeScope = GKLeaderboardTimeScopeAllTime;
board.playerScope = GKLeaderboardPlayerScopeGlobal;
board.category = #"myGCCategory";
[board loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
if(error != nil) {
NSLog(#"Error loading score:\n%#", [error localizedDescription]);
}
if(scores != nil) {
for(int i=0; i<[scores count]; i++) {
GKScore *score = (GKScore *)[scores objectAtIndex:i];
if(([score.playerID isEqualToString:myGCPlayerID]) &&
(score.value > playerLastScore)) {
playerLastScore = score.value;
}
}
}
}];
[board release];
You may also apply a more optimized score loop as it is in your code. I hope this helps.