ALAsset NSURL *assetURL returns NULL - iphone

I'm having a weird issue trying to save an image to my SavedPhotosAlbum using the ALAssetsLibrary, particularly when I'm using the writeImageToSavedPhotosAlbum method.
Basically my issue is that the NSURL is returning null within my completion block... there is no Error, but the URL is null.
Here's the method :
UIImage *imageToSave = [libraryPicture imageFromCurrentlyProcessedOutput];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum:[imageToSave CGImage] orientation:ALAssetOrientationUp completionBlock:^(NSURL *assetURL, NSError *error) {
NSLog(#"AssetURL: %#", assetURL);
if(!error) {
NSLog(#"\t ! Error");
NSLog(#"\t Error: %#", [error localizedDescription]);
NSLog(#"\t Error code %d", [error code]);
}
if(error != nil) {
NSLog(#"\t ERROR != NIL");
NSLog(#"\t Error - Image Failed To Save With Error: %#", [error localizedDescription]);
NSLog(#"\t Error code %d", [error code]);
}
if(error == nil) {
NSLog(#"\t ERROR == NIL");
}
}];
I use a pretty similar method just a few lines away (in another switch case) that works, and it prints the URL within an almost identical completion block (though the called method differs):
[stillCamera capturePhotoAsJPEGProcessedUpToFilter:selectedFilter withCompletionHandler:^(NSData *processedJPEG, NSError *error) {
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageDataToSavedPhotosAlbum:processedJPEG metadata:stillCamera.currentCaptureMetadata completionBlock:^(NSURL *assetURL, NSError *error2) {
if (error2 != nil) {
NSLog(#"ERROR: the image failed to be written");
}
else {
NSLog(#"PHOTO SAVED FROM STILL CAMERA - assetURL: %#", assetURL);
}
}];
}];

If you really are seeing the behaviour you state, this would appear to be the Asset Library breaking its API contract. You should file a radar with Apple with an example project that demonstrates this, and perhaps also file a DTS incident for a speedier response.

Related

Not able to post on Facebook using Facebook sdk in iOS 7

I am getting an issue while posting a feed on Facebook using Facebook sdk in ios7.
I have copied the code from Facebook samples provided on Github. But whenever I tried to post on Facebook, a message appears as "An error occurred. Please try again later". And then I have to close the web view.
Please find the code below:
NSMutableDictionary *params123 = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"Roasted pumpkin seeds", #"name",
#"Healthy snack.", #"caption",
#"Crunchy pumpkin seeds roasted in butter and lightly salted.", #"description",
#"http://example.com/roasted_pumpkin_seeds", #"link",
#"http://i.imgur.com/g3Qc1HN.png", #"picture",
nil];
// Show the feed dialog
[FBWebDialogs presentFeedDialogModallyWithSession:nil
parameters:params123
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
NSLog(#"Error publishing story: %#", error.description);
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
// User cancelled.
NSLog(#"User cancelled.");
} else {
// Handle the publish feed callback
NSDictionary *urlParams = [self parseURLParams:[resultURL query]];
if (![urlParams valueForKey:#"post_id"]) {
// User cancelled.
NSLog(#"User cancelled.");
} else {
// User clicked the Share button
NSString *result = [NSString stringWithFormat: #"Posted story, id: %#", [urlParams valueForKey:#"post_id"]];
NSLog(#"result %#", result);
}
}
}
}];
}
Note: I am using the updated version of Facebook sdk for iOS 7
Why do you use a webdialog ?
Here is what I use
NSArray *urlsArray = [NSArray arrayWithObjects:#"myurl1", nil];
NSURL *imageURL = [NSURL URLWithString:#"http://url/to/image.png"];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];
NSArray *imagesArray = [NSArray arrayWithObjects:image, nil];
[FBDialogs presentOSIntegratedShareDialogModallyFrom:self
session:nil
initialText:#"My message for facebook"
images:imagesArray
urls:urlsArray
handler:^(FBOSIntegratedShareDialogResult result, NSError *error) {
NSLog(#"Result : %u", result);
if (error != nil) {
NSLog(#"Error : %#", [error localizedDescription]);
}
}];

Saving Video in an Album Created

i have created an album using this code in AppDelegate methode
NSString *albumName=#"999Videos";
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library addAssetsGroupAlbumWithName:albumName
resultBlock:^(ALAssetsGroup *group) {
NSLog(#"added album:%#", albumName);
}
failureBlock:^(NSError *error) {
NSLog(#"error adding album");
}];
Now i want to save the recorded videos to this 999Videos album created.Not to the photosAlbum which i have done like this.
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:outputFileURL])
{
[library writeVideoAtPathToSavedPhotosAlbum:outputFileURL
completionBlock:^(NSURL *assetURL, NSError *error)
The videos are saving but not in the 999Videos album.Could someone please tell me how can i save the videos to my custom album?
After tearing my hair out over this finally i found the solution.Here is my code.
NSString *albumName=#"999 Videos";
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library addAssetsGroupAlbumWithName:albumName
resultBlock:^(ALAssetsGroup *group) {
NSLog(#"added album:%#", albumName);
}
failureBlock:^(NSError *error) {
NSLog(#"error adding album");
}];
__block ALAssetsGroup* groupToAddTo;
[library enumerateGroupsWithTypes:ALAssetsGroupAlbum
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if ([[group valueForProperty:ALAssetsGroupPropertyName] isEqualToString:albumName]) {
NSLog(#"found album %#", albumName);
groupToAddTo = group;
}
}
failureBlock:^(NSError* error) {
NSLog(#"failed to enumerate albums:\nError: %#", [error localizedDescription]);
}];
[library assetForURL:assetURL
resultBlock:^(ALAsset *asset) {
// assign the photo to the album
[groupToAddTo addAsset:asset];
NSLog(#"Added %# to %#", [[asset defaultRepresentation] filename], albumName);
}
failureBlock:^(NSError* error) {
NSLog(#"failed to retrieve image asset:\nError: %# ", [error localizedDescription]);
}];

issue with NSOperationQueue, weakSelf and blocks

I have the following code:
[[AHPinterestAPIClient sharedClient] getPath:requestURLPath parameters:nil
success:^(AFHTTPRequestOperation *operation, id response) {
[weakSelf.backgroundQueue_ addOperationWithBlock:^{
[self doSomeHeavyComputation];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[weakSelf.collectionView_ setContentOffset:CGPointMake(0, 0)];
[weakSelf.collectionView_ reloadData];
[weakSelf.progressHUD_ hide:YES];
[[NSNotificationCenter defaultCenter] performSelector:#selector(postNotificationName:object:) withObject:#"UIScrollViewDidStopScrolling" afterDelay:0.3];
[weakSelf.progressHUD_ hide:YES];
}];
}];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[weakSelf.progressHUD_ hide:YES];
[weakSelf.collectionView_.pullToRefreshView stopAnimating];
NSLog(#"Error fetching user data!");
NSLog(#"%#", error);
}];
For some reason this worked just fine in iOS 5, but not iOS 6 (it crashes). Now I am not going to ask about iOS 6 because it's still under NDA. What I want to know is, whether the code above is wrong? If yes how do I fix it.
If I put the code inside the block outside of the mainQueue then it's fine.
What I am trying to do here is to do the NSOperationQueue mainQueue only after the [self doSomeHeavyComputation] is done. So this is a dependency, how should I add this dependency?
Update:
Here's the crash log if it helps:
It is recommended to “unwind” weak references in the block, so please try this:
__weak id weakSelf = self;
[client getPath:path parameters:nil success:^(id op, id response) {
id strongSelf = weakSelf;
if (strongSelf == nil) return;
__weak id internalWeakSelf = strongSelf;
[strongSelf.backgroundQueue_ addOperationWithBlock:^{
id internalStrongSelf = internalWeakSelf;
if (internalStrongSelf == nil) return;
[internalStrongSelf doSomeHeavyComputation];
__weak id internalInternalWeakSelf = internalStrongSelf;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
id internalInternalStrongSelf = internalInternalWeakSelf;
if (internalInternalStrongSelf == nil) return;
[internalInternalStrongSelf reloadCollectionView];
}];
}];
}
failure:^(id op, NSError *error) {
id strongSelf = weakSelf;
if (strongSelf == nil) return;
[strongSelf stopProgress];
NSLog(#"Error fetching user data: %#", error);
}];

How to check if an ALAsset still exists using a URL

I've got an array containing ALAsset urls (not full ALAsset objects)
So each time I start my application I want to check my array to see if it's still up to date...
So I tried
NSData *assetData = [[NSData alloc] initWithContentsOfFile:#"assets-library://asset/asset.PNG?id=1000000001&ext=PNG"];
but assetData is allways nil
thx for the help
Use assetForURL:resultBlock:failureBlock: method of ALAssetsLibrary instead to get the asset from its URL.
// Create assets library
ALAssetsLibrary *library = [[[ALAssetsLibrary alloc] init] autorelease];
// Try to load asset at mediaURL
[library assetForURL:mediaURL resultBlock:^(ALAsset *asset) {
// If asset exists
if (asset) {
// Type your code here for successful
} else {
// Type your code here for not existing asset
}
} failureBlock:^(NSError *error) {
// Type your code here for failure (when user doesn't allow location in your app)
}];
Having assets path you can use this function to check if image exist:
-(BOOL) imageExistAtPath:(NSString *)assetsPath
{
__block BOOL imageExist = NO;
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:[NSURL URLWithString:assetsPath] resultBlock:^(ALAsset *asset) {
if (asset) {
imageExist = YES;
}
} failureBlock:^(NSError *error) {
NSLog(#"Error %#", error);
}];
return imageExist;
}
Remember that checking if image exist is checking asynchronyus.
If you want to wait until new thread finish his life call function "imageExistAtPath" in main thread:
dispatch_async(dispatch_get_main_queue(), ^{
[self imageExistAtPath:assetPath];
});
Or you can use semaphores, but this is not very nice solution:
-(BOOL) imageExistAtPath:(NSString *)assetsPath
{
__block BOOL imageExist = YES;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_async(queue, ^{
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:[NSURL URLWithString:assetsPath] resultBlock:^(ALAsset *asset) {
if (asset) {
dispatch_semaphore_signal(semaphore);
} else {
imageExist = NO;
dispatch_semaphore_signal(semaphore);
}
} failureBlock:^(NSError *error) {
NSLog(#"Error %#", error);
}];
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return imageExist;
}
For iOS 8 or later, there is a synchronous method to check if an ALAsset exists.
#import Photos;
if ([PHAsset fetchAssetsWithALAssetURLs:#[assetURL] options:nil].count) {
// exist
}
Swift:
import Photos
if PHAsset.fetchAssetsWithALAssetURLs([assetURL], options: nil).count > 0 {
// exist
}
Swift 3:
import Photos
if PHAsset.fetchAssets(withALAssetURLs: [assetURL], options: nil).count > 0 {
// exist
}
Use this method to check if file exists
NSURL *yourFile = [[self applicationDocumentsDirectory]URLByAppendingPathComponent:#"YourFileHere.txt"];
if ([[NSFileManager defaultManager]fileExistsAtPath:storeFile.path
isDirectory:NO]) {
NSLog(#"The file DOES exist");
} else {
NSLog(#"The file does NOT exist");
}

problems saving to persistent storage iphone

I am writing an iphone app; I need to save the data to persistent storage, but I am having the problems...
I created an entity in xcdatamodel and I have no problem getting the default value set for my attribute. In my testing, I go thru the code several times below and can change this attribute (it's an integer) while the application is active. However, when I close and reopen the app, my integer (myInt) is back to the default value when I expected it to be the last value I updated it to.
Here is what I am doing:
NSManagedObjectContext *managedObjectContext = appDelegate.managedObjectContext;
NSEntityDescription *myTestEntity = [NSEntityDescription
entityForName:#"TestEntity"
inManagedObjectContext:managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:timeStampEntity];
NSError *error = nil;
NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
// TODO: Handle the error
}
for (id oneObject in fetchedObjects)
{
NSInteger myInt = [[oneObject valueForKey:#"myStoredInt"]intValue];
myInt++;
[oneObject setValue:[NSNumber numberWithInt: myInt] forKey:#"myStoredInt"];
NSError *error = nil;
if (![managedObjectContext save:&error]) {//TODO: Handle error
}
}
[fetchRequest release];
I was hoping that line:
if (![managedObjectContext save:&error])
would do the job and store the changes to the persistent storage, but it does not! (Having this line inside or outside the for loop does not change the result)
What am I doing wrong?
Thank you very much for your help!
It will be helpful if you could show your app delegate code. My guess is that somewhere you are reseting the data your self. maybe in the method that you load the start data.
3 notes for now:
you don't need to place the save
method inside the loop. you should
place it after all the changes are
made and just once.
check if you have a save method called in the (if not add them):
- (void)applicationWillTerminate:(UIApplication*)application {
[self saveContext];
}
- (void)applicationDidEnterBackground:(UIApplication*)application {
[self saveContext];
}
if it dose not help try to see if you are loading the default values on every lunch of the app.
GOOD LUCK
and welcome
EDIT
Hey, you can do that -
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSURL *storeURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"anyname.sqlite"]];
//check if the store already exist?
BOOL firstRun = NO;
if (![[NSFileManager defaultManager] fileExistsAtPath:[storeURL path] isDirectory:NULL]) {
firstRun = YES;
}
NSError *error = nil;
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
if(firstRun){
//add your default data here
}
}