I'm using this method to load all achievements description.
[GKAchievementDescription loadAchievementDescriptionsWithCompletionHandler:
^(NSArray *descriptions, NSError *error) {
CCLOG(#"achivements loaded");
if (error != nil) {
NSLog(#"Error %#", error);
} else {
if (descriptions != nil){
CCLOG(#"nb %i",descriptions.count);
for (GKAchievementDescription* a in descriptions) {
CCLOG(#"image %# %# %#", a.title, a.achievedDescription, a.image);
[achievementsDescDictionary setObject: a forKey: a.identifier];
}
} else {
CCLOG(#"descriptions empty");
}
}
}];
I always get a.image = null.
Thanks.
Actually you can't load images from Game Center.
Just add your achievements Images into your project and use this method with GKAchievementHandler
- (void)notifyAchievementTitleAndImage:(NSString *)title andMessage:(NSString *)message withImage:(UIImage *)image
if you can't load the images from game center then what about to create a plist file for mapping "achievements-images"? I used this technique for my game which is similar to 3-in-row to define various types of blocks
Related
I've been following this tutorial http://www.touch-code-magazine.com/ios5-saving-photos-in-custom-photo-album-category-for-download/ to save an image to a custom album. This works fine but it's saving to both the camera roll and my custom album.
Looking at the code it seems like this is a necessary step, as after saving the image to the camera roll we have an ALAsset that can be used with the ALAssetsGroup addAsset: method.
Is there a way that I can add an image to a custom album without adding it to the camera roll?
Currently using this code:
-(void)saveImage:(UIImage*)image toAlbum:(NSString*)albumName withCompletionBlock:(SaveImageCompletion)completionBlock
{
//write the image data to the assets library (camera roll)
[self writeImageToSavedPhotosAlbum:image.CGImage orientation:(ALAssetOrientation)image.imageOrientation
completionBlock:^(NSURL* assetURL, NSError* error) {
//error handling
if (error!=nil) {
completionBlock(error);
return;
}
//add the asset to the custom photo album
[self addAssetURL: assetURL
toAlbum:albumName
withCompletionBlock:completionBlock];
}];
}
-(void)addAssetURL:(NSURL*)assetURL toAlbum:(NSString*)albumName withCompletionBlock:(SaveImageCompletion)completionBlock
{
__block BOOL albumWasFound = NO;
//search all photo albums in the library
[self enumerateGroupsWithTypes:ALAssetsGroupAlbum
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
//compare the names of the albums
if ([albumName compare: [group valueForProperty:ALAssetsGroupPropertyName]]==NSOrderedSame) {
//target album is found
albumWasFound = YES;
//get a hold of the photo's asset instance
[self assetForURL: assetURL
resultBlock:^(ALAsset *asset) {
//add photo to the target album
[group addAsset: asset];
//run the completion block
completionBlock(nil);
} failureBlock: completionBlock];
//album was found, bail out of the method
return;
}
if (group==nil && albumWasFound==NO) {
//photo albums are over, target album does not exist, thus create it
__weak ALAssetsLibrary* weakSelf = self;
//create new assets album
[self addAssetsGroupAlbumWithName:albumName
resultBlock:^(ALAssetsGroup *group) {
//get the photo's instance
[weakSelf assetForURL: assetURL
resultBlock:^(ALAsset *asset) {
//add photo to the newly created album
[group addAsset: asset];
//call the completion block
completionBlock(nil);
} failureBlock: completionBlock];
} failureBlock: completionBlock];
//should be the last iteration anyway, but just in case
return;
}
} failureBlock: completionBlock];
}
Turns out there isn't - images will always be written to the camera roll by default.
I am having issues when I try to do "save" with MagicalRecord. My code:
- (void) findInternetObject {
[InternetObjectFinder runBlockSuccess:^(NSManagedObject *obj) {
obj.attr1 = #"abc";
[[NSManagedObjectContext MR_defaultContext] MR_saveErrorHandler:^(NSError *error) {
NSLog(#"failed to save attr1, Error: %#, %#", error.localizedDescription, error.userInfo);
}];
}];
}
where obj was created in method "runBlockSuccess" method in "InternetObjectFinder" class:
InternetObject *obj = [InternetObject MR_createEntity];
The app crashes at line:
[NSManagedObjectContext MR_defaultContext] MR_saveErrorHandler
with error: EXC_BAD_ACCESS
Any help is appreciated.
It seems to be a scope issue inside your nested blocks,
have you tried to write something like this (not tested):
- (void) findInternetObject {
NSManagedObjectContext *defaultContext = [NSManagedObjectContext MR_defaultContext];
[InternetObjectFinder runBlockSuccess:^(NSManagedObject *obj) {
obj.attr1 = #"abc";
[defaultContext MR_saveErrorHandler:^(NSError *error) {
NSLog(#"failed to save attr1, Error: %#, %#", error.localizedDescription, error.userInfo);
}];
}];
}
If the proble persist maybe this detailed answer can help you:
How do I avoid capturing self in blocks when implementing an API?
You should call save method on main thread. Your code looks that you are saving core data into block. If that doesn't work you can use below code to save.
MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
} completion:^(BOOL success, NSError *error) {
if(success){
NSLog(#"success");
}
}];
Part of my app has a photo browser, somewhat similar to Apple's Photos app, with an initial view controller to browse photo thumbnails and a detail view that's shown when you tap on a photo.
I'm using ALAssetsLibrary to access photos, and I pass an array of ALAsset URL's to my detail view controller so you can swipe from one photo to the next.
Everything works great, until I receive an ALAssetsLibraryChangedNotification while swiping from one photo to another (in the detail view controller), which often results in a crash:
NOTIFICATION: the asset library changed // my own NSLog for when the
notification occurs
loading assets... // my own NSLog for when I start reloading assets in
the thumbnail browser
Assertion failed: (size == bytesRead), function
-[ALAssetRepresentation _imageData], file /SourceCache/AssetsLibrary/MobileSlideShow-1373.58.1/Sources/ALAssetRepresentation.m,
line 224.
The specific line of code it crashes on, is in calling [currentRep metadata] as shown here:
- (void)someMethod {
NSURL *assetURL = [self.assetURLsArray objectAtIndex:index];
ALAsset *currentAsset;
[self.assetsLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) {
[self performSelectorInBackground:#selector(configureDetailViewForAsset:) withObject:asset];
} failureBlock:^(NSError *error) {
NSLog(#"failed to retrieve asset: %#", error);
}];
}
- (void)configureDetailViewForAsset:(ALAsset *)currentAsset {
ALAssetRepresentation *currentRep = [currentAsset defaultRepresentation];
if (currentAsset != nil) {
// do some stuff
}
else {
NSLog(#"ERROR: currentAsset is nil");
}
NSDictionary *metaDictionary;
if (currentRep != nil) {
metaDictionary = [currentRep metadata];
// do some other stuff
}
else {
NSLog(#"ERROR: currentRep is nil");
}
}
I understand that once a notification is received, it invalidates any references to ALAsset and ALAssetRepresentation objects... but how am I supposed to deal with the situation where it invalidates something right in the middle of trying to access it?
I've tried setting a BOOL, right when receiving the notification to completely abort and prevent [currentRep metadata] from ever being called, but even that doesn't catch it every time:
if (self.receivedLibraryChangeNotification) {
NSLog(#"received library change notification, need to abort");
}
else {
metaDictionary = [currentRep metadata];
}
Is there anything I can do? At this point I'm almost ready to give up on using the ALAssetsLibrary framework.
(note this unresolved thread on the Apple dev forums describing the same issue: https://devforums.apple.com/message/604430 )
It seems the problem is around here:
[self.assetsLibrary assetForURL:nextURL
resultBlock:^(ALAsset *asset) {
// You should do some stuff with asset at this scope
ALAssetRepresentation *currentRep = [asset defaultRepresentation];
// Assume we have a property for that
self.assetRepresentationMetadata = [currentRep metadata];
...
// assume we have a method for that
[self updateAssetDetailsView];
}
failureBlock:^(NSError *error) {
NSLog(#"failed to retrieve asset: %#", error);
}];
Once you have got user asset it is better to copy asset information by providing necessary data to your details controller subviews or by caching for later use. It can be helpful for avoiding ALAsset invalidation troubles. When notification ALAssetsLibraryChangedNotification sent you may need to discard details controller and query the Library content from the beginning.
I have an App which stores images to Custom Library in Photo Album in iphone.
I called the following Function of ALAssetLibrary
-(void)saveImage:(UIImage*)image toAlbum:(NSString*)albumName withCompletionBlock:(SaveImageCompletion)completionBlock
{
//write the image data to the assets library (camera roll)
[self writeImageToSavedPhotosAlbum:image.CGImage orientation:(ALAssetOrientation)image.imageOrientation
completionBlock:^(NSURL* assetURL, NSError* error) {
//error handling
if (error!=nil) {
completionBlock(error);
return;
}
//add the asset to the custom photo album
[self addAssetURL: assetURL
toAlbum:albumName
withCompletionBlock:completionBlock];
}];
}
in my SaveImage IBAction
-(IBAction)saveToLib:(id)sender
{
UIImage *savedImage = imgPicture.image;
NSLog(#"Saved Image%#",savedImage);
[self.library saveImage:savedImage toAlbum:#"Touch Code" withCompletionBlock:^(NSError *error) {
if (error!=nil) {
NSLog(#"Big error: %#", [error description]);
}
}];
}
but my application keep getting Crashed
Help me out
Thanks in Advance
It seems that you are not calling the [self.library saveImage:savedImage toAlbum:#....] correctly. If you are following this web site, add #import "ALAssetsLibrary+CustomPhotoAlbum.h" in your view controller.
Not sure if it is the problem. Sorry if this workaround is the wrong approach.
Problem is the file from the website he downloaded.
I had the same issue and rewriting the code myself solved this.
Maybe encoding or something like this...
In my app (which worked under iOS 4) I collect pictures selected via UIImagePickerController. Unfortunately, I have a strange problem after upgrading to iOS 5.
In a nutshell, I store ALAssetRepresentation in NSMutableArray. When I add photos from Library, everything is ok. However, when I capture and save a picture, all ALAssetRepresentations (including a new one) become 0-sized. ALAssetRepresentation.size and ALAssetRepresentation.getBytes:fromOffset:length:error: return 0 and getBytes:error is nil.
I init ALAssetsLibrary in AppDelegate, so the
“The lifetimes of objects you get back from a library instance are tied to the lifetime of the library instance.” condition is OK.
Is there a way to prevent ALAssetRepresentation from zeroing? Or how can I read image by bytes after this?
My code:
-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
if ([picker sourceType] == UIImagePickerControllerSourceTypePhotoLibrary){
[self addPhoto:[info valueForKey:UIImagePickerControllerReferenceURL]];
}
else if ([picker sourceType] == UIImagePickerControllerSourceTypeCamera){
[self savePhoto:[info valueForKey:UIImagePickerControllerOriginalImage]];
}
[self dismissModalViewControllerAnimated:YES];
}
-(ALAssetsLibrary*) getLibrary{
if (!library){
testAppDelegate *appDelegate = (testAppDelegate *)[[UIApplication sharedApplication] delegate];
library = appDelegate.library;
}
NSLog(#"getLibrary: %#", library);
return library;
}
-(void) addPhoto:(NSURL*) url{
ALAssetsLibraryAssetForURLResultBlock successBlock = ^(ALAsset *asset_){
ALAssetRepresentation *assetRepresentation = [[asset_ defaultRepresentation] retain];
[photos addObject: assetRepresentation];
};
ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError *error){
NSLog(#"Error: Cannot get image. %#", [error localizedDescription]);
};
[[self getLibrary] assetForURL:url resultBlock:successBlock failureBlock:failureBlock];
}
- (void)savePhoto:(UIImage *)image {
[[self getLibrary] writeImageToSavedPhotosAlbum:[image CGImage] orientation:[image imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error) {
if (error) {
NSLog(#"Error: Cannot save image. %#", [error localizedDescription]);
} else {
NSLog(#"photo saved");
[self addPhoto:assetURL];
}
}];
}
I solved it!
ALAssetsLibraryChangedNotification
Sent when the contents of the assets library have changed from under the app that is using the data.
When you receive this notification, you should discard any cached information and query the assets library again. You should consider invalid any ALAsset, ALAssetsGroup, or ALAssetRepresentation objects you are referencing after finishing processing the notification.
Have you tried retaining the ALAssets instead of the ALAssetRepresentation? This should work, I have used this approach before.