ALAssetsLibraryWriteVideoCompletionBlock is returning undefined values. If assetURL is equal to nil, then error ought to be not equal to nil, that is, return to me some error description.
See apple documentation at here.
When I record small video, ALAssetsLibraryWriteVideoCompletionBlock return a good value of assetURL, but when I record long video 3 or 4 Gb, assetURL return nil and error return nil. Video recorded is in tmp file because I can see this video in temporally folder in my app. It seems like IOS framework try to do a copy of this temporally file to photo album and iPhone don't have enough memory to copy this temp file to photo album and return a path of this file (assetURL).
Is this a bug in iOS framework? If so, is there a way to fix it?
UPDATE:
My files is less than 4GB. Thanks
UPDATE with source code:
-(void)recorder:(AVCamRecorder *)recorder recordingDidFinishToOutputFileURL:(NSURL *)outputFileURL error:(NSError *)error
{
if ([[self recorder] recordsAudio] && ![[self recorder] recordsVideo]) {
// If the file was created on a device that doesn't support video recording, it can't be saved to the assets
// library. Instead, save it in the app's Documents directory, whence it can be copied from the device via
// iTunes file sharing.
[self copyFileToDocuments:outputFileURL];
if ([[UIDevice currentDevice] isMultitaskingSupported]) {
[[UIApplication sharedApplication] endBackgroundTask:[self backgroundRecordingID]];
}
if ([[self delegate] respondsToSelector:#selector(captureManagerRecordingFinished:)]) {
[[self delegate] captureManagerRecordingFinished:self];
}
}
else {
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:outputFileURL
completionBlock:^(NSURL *assetURL, NSError *error) {
if (error) {
if ([[self delegate] respondsToSelector:#selector(captureManager:didFailWithError:)]) {
[[self delegate] captureManager:self didFailWithError:error];
}
}
if ([[UIDevice currentDevice] isMultitaskingSupported]) {
[[UIApplication sharedApplication] endBackgroundTask:[self backgroundRecordingID]];
}
if (assetURL!=nil)
{
if ([[self delegate] respondsToSelector:#selector(captureManagerRecordingFinished:)]) {
[[self delegate] captureManagerRecordingFinished:self];
}
}
else
{
NSLog(#"Video is not saved");
NSString *alertMsg = [NSString stringWithFormat:#"Impossible to copy video to photo album"];
UIAlertView *alert = [[UIAlertView alloc] init];
[alert setTitle:#"info"];
[alert setMessage:alertMsg];
[alert setDelegate:self];
[alert addButtonWithTitle:#"Accept"];
[alert show];
}
}];
}
}
I have almost the same issue: just that I try to save photos, not movies; but still assetURL is NULL. Here is my code:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
ALAssetsLibrary *library = [[ALAssetsLibrary alloc]init];
[library writeImageToSavedPhotosAlbum:(__bridge CGImageRef)([info objectForKey:UIImagePickerControllerOriginalImage])
orientation:ALAssetOrientationUp completionBlock:^(NSURL *assetURL, NSError *error) {
if(error == nil) {
_myImageUrl = [NSString stringWithFormat:#"%#",assetURL];
NSLog(#"%#",assetURL);
} else NSLog(#"%#",error);
}];
[picker dismissViewControllerAnimated:YES completion:nil];
}
So, I guess this issue is not related to the size of the file..
I do different tests and I can save videos with more than 2Gb. In this case I delete a lot of files in my iPhone until I had 7Gb, then I saved a video with 3.2Gb (3.8Gb free) and store in photo gallery. Then I saved other video with 2Gb and it didn't save in photo gallery. What does it means?. Well, when you are saving a temp video, then you need at least the same or more free space than the video that you are trying to copy to photo gallery.
The problem here is that IOS7 framework doesn't return any error with his function writeVideoAtPathToSavedPhotosAlbum, in this case it have to return ALAssetsLibraryWriteDiskSpaceError = -3305. Maybe in previous version of IOS framework it works...but in IOS7 not.
By the way, I open a ticket in apple bug reporter. If they tell me something different I will post it.
Thanks for all guys.
ADD: FYI, I save a video file with more than 4Gb (4.6Gb) in IOS 7.0.3
Related
When a user uploads a picture from the iPhone gallery, I extract the location using ALAssetsLibrary:
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL:urlPhoto
resultBlock:^(ALAsset *asset) {
CLLocation *location = [asset valueForProperty:ALAssetPropertyLocation];
} failureBlock:^(NSError *error) {
NSLog(#"Can not get asset - %#",[error localizedDescription]);
}];
However, if the user uploads a picture and then returns to the upload screen and upload another, after three or four uploads the app crashes on EXC_BAD_ACCESS, when running the assetForURL:resultBlock:failureBlock: method.
I guess it happens since the assetForURL:resultBlock:failureBlock: runs async and the ALAssetsLibrary is released for some reason, though it cannot run simultaneously the way I've built the app.
How can I prevent it from crashing?
EDIT
Although the crash was always at this point (due to the earlier dismiss), the error occurred because of a UITableView that was deallocated earlier, but at this point referred to its delegate/datasource.
the fix was adding:
- (void) dealloc
{
myTableView.dataSource = nil;
myTableView.delegate = nil;
}
at the end of the UIViewController that had the TableView.
Just change your object to property .
interface:
#property (nonatomic, strong) ALAssetsLibrary* assetslibrary;
Than call implementation:
if (self.assetslibrary == nil) {
self.assetslibrary = [[ALAssetsLibrary alloc] init];
}
[self.assetslibrary assetForURL:urlPhoto
resultBlock:^(ALAsset *asset) {
CLLocation *location = [asset valueForProperty:ALAssetPropertyLocation];
} failureBlock:^(NSError *error) {
NSLog(#"Can not get asset - %#",[error localizedDescription]);
}];
In iOS app,
Anytime I call this function to open app store,
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"itms-apps://app-url"]];
The Original app will be deactivated.
The user will then have to restart the original app after they exit the App Store.
It’s very inconvenient way of installation.
Is there any way to open App Store links without leaving the app?
For example, opened as popup window,
after installation just close the popup window, and I can see the original app.
Updated :
I found a great example!
Like this game's popup.
Yes, we can open an App store link without leaving the existing app in IOS 6+.
you can use below for it.
#import <StoreKit/StoreKit.h>
SKStoreProductViewController *storeController = [[SKStoreProductViewController alloc] init];
storeController.delegate = delegate;
NSDictionary *productParameters = #{ SKStoreProductParameterITunesItemIdentifier : appStoreID };
[storeController loadProductWithParameters:productParameters completionBlock:^(BOOL result, NSError *error) {
//Handle response
}
Thanks
My version is here.
1) #import <StoreKit/StoreKit.h> and set SKStoreProductViewControllerDelegate
2) add delegate response method,
- (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController
{
// if user do cancel, close it
[viewController dismissViewControllerAnimated:YES completion:nil];
}
3) add store open code.
void SomeClassName::openAppStore(string appStoreId, string appUrl)
{
// below iOS 6.0
NSString *appUrlStatic = [NSString stringWithUTF8String:appUrl.c_str()];
// iOS 6.0 or above, appstore id is 9-digin number
NSString *appId = [NSString stringWithUTF8String:appStoreId.c_str()];;
// check SKStoreProductViewController API exist or not
if(NSClassFromString(#"SKStoreProductViewController")) {
SKStoreProductViewController *storeController = [[SKStoreProductViewController alloc] init];
storeController.delegate = self;
NSDictionary *productParameters = #{ SKStoreProductParameterITunesItemIdentifier : appId };
[storeController loadProductWithParameters:productParameters completionBlock:^(BOOL result, NSError *error) {
if (result) {
[self presentViewController:storeController animated:YES completion:nil];
} else {
[[[UIAlertView alloc] initWithTitle:#"Error Occur"
message:#"Error to open App Store."
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles: nil] show];
}
}];
[storeController release];
} else {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:appUrlStatic]];
}
}
I have an image and i want to save that image into custom photo album.
My code is working fine for Iphone but it is not workin for iPad.
self.library = [[ALAssetsLibrary alloc] init];
[self.library saveImage:imageShow.image toAlbum:#"APP NAME" withCompletionBlock:^(NSError *error) {
if (error!=nil) {
NSLog(#"Big error: %#", [error description]);
}
}];
just help me please
Thanx for help..
I am currently in the process in creating a new app which analyses certain aspects of the user and makes the funny.
I am stuck on one part though, at the end of the app, when the user gets their results back, I want it so they can save it to a custom Album specifically for screenshots from this app.
-(IBAction)save:(id)sender {
toolBar.hidden = YES;
[self performSelector:#selector(screenPause) withObject:nil afterDelay:0.001];
}
-(void)screenPause {
UIGraphicsBeginImageContext(self.view.bounds.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
screenshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(screenshotImage, nil, nil, nil);
[self performSelector:#selector(screenPauseOne) withObject:nil afterDelay:0.001];
}
This is how I am currently capturing the screen. And as you can see, I am just saving it to the default album. How would I create a new album and then place captured images into it?
Thanks in advance,
Rafee
You need to use the AssetsLibrary framework.
Here is a tutorial that explains how to do it:
http://www.touch-code-magazine.com/ios5-saving-photos-in-custom-photo-album-category-for-download/
To my understanding what phix23 is telling you is that the code you are looking for is:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo
{
[self.library saveImage:image toAlbum:#"YourCustomAlbumName" withCompletionBlock:^(NSError *error) {
if (error!=nil)
{
NSLog(#"Big error: %#", [error description]);
}
}];
[picker dismissModalViewControllerAnimated:NO];
}
The block code starting with [self is where the magic happens.
I'm using writeImageToSavedPhotosAlbum:orientation:completionBlock: to save an image and it's ok. Then I want an array of assets in the Album.
The first time I refresh my array it doesn't count the new image, while calling it a second time it works fine.
Why? I understand that the writeImageToSavedPhotosAlbum start another thread and that the Block is called after the save operation completes, isn't it?
This is the code I use to save the image and refresh my array:
[_album refresh];
ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum:image
metadata:metadataAsMutable
completionBlock:^(NSURL *assetURL, NSError *error) {
if (error) {
NSLog(#"ERROR: the image failed to be written");
}
else {
NSLog(#"PHOTO SAVED - assetURL: %#", assetURL);
}
[_album refresh];
[_album refresh];
[spinner stopAnimating];
[self close];
}];
This is the refresh function:
- (void)refresh {
[_imgAssets removeAllObjects];
if (_albumGroup) {
[_albumGroup enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if(result == nil) {
NSLog(#"done enumerating photos (%d)", [_imgAssets count]);
return;
}
[_imgAssets addObject:result];
//NSLog(#">> enumerating photos (%d)", [_imgAssets count]);
}];
}
}
And this is what I obtain:
2013-06-04 23:19:07.962 PhotInfo[4835:c07] done enumerating photos (29)
2013-06-04 23:19:08.041 PhotInfo[4835:c07] PHOTO SAVED - assetURL: assets-library://asset/asset.JPG?id=CDC2E97A-FF47-4A52-99E2-574037155D92&ext=JPG
2013-06-04 23:19:08.042 PhotInfo[4835:c07] done enumerating photos (29)
2013-06-04 23:19:08.044 PhotInfo[4835:c07] done enumerating photos (30)
Moreover, if I replace the second of the 3 refresh with
[_album performSelectorOnMainThread:#selector(refresh) withObject:nil waitUntilDone:YES];
it may or may not read the added image.
Where is the problem?
Thanks for the help.
I've resolved setting an observer on ALAssetsLibraryChangedNotification.