How to check if an ALAsset still exists using a URL - iphone

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");
}

Related

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]);
}];

How to know image present at the url

I have url for image picked using ELCImagePickerController. I stored the url for future reference.
I get that URL using:
[dict valueForKey:UIImagePickerControllerReferenceURL];
Now the problem arises when after some time user deleted that particular image from photo library
and I am going to access that image using URL.
My app does not get crashed.
I have tried using NSUrl method
[imagePath checkResourceIsReachableAndReturnError:&err]
as well i tried something like:
-(BOOL)findImage:(NSURL*)path
{
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
__block BOOL flag=YES;
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
{
ALAssetRepresentation *rep = [myasset defaultRepresentation];
CGImageRef iref = [rep fullScreenImage];
if (iref) {
flag=YES;
dispatch_group_leave(group);
}
};
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror)
{
NSLog(#"cant get image - %#",[myerror localizedDescription]);
flag=NO;
};
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL:path resultBlock:resultblock failureBlock:failureblock];
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);
[assetslibrary release];
return flag;
}
Sample url :
assets-library://asset/asset.JPG?id=E862927E-E646-448A-9EB6-A7D48668B3DC&ext=JPG
But no success.
How to know that image present at particular URL.
If any one can help me out on this will be appreciable.
Thanks in advance.
For this case you need to check ALAssetRepresentation *rep = [myasset defaultRepresentation] to nil.
if(rep != nil){
//write your code..
}
Solved the problem with change in the findImage method
-(BOOL)findImage:(NSURL*)path
{
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
__block BOOL flag=YES;
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL:path resultBlock:^(ALAsset *asset) {
if (asset==nil)
{
flag=NO;
}
else
{
flag=YES;
}
dispatch_group_leave(group);
} failureBlock:^(NSError *error){
NSLog(#"operation was not successfull!");
dispatch_group_leave(group);
}];
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);
[assetslibrary release];
return flag;
}

ALAssetsLibrary is too slow - Objective-C

What is a fast way to load 10-20 fullscreen images from a camera roll, saved photos?
I'm using this code, but to load 10 photos I need to wait about 5-10 seconds. I'm using iPhone 4S.
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if(_savedPhotos.count>=11) *stop = YES;
[group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *needToStop) {
NSLog(#"%d",index);
if(_savedPhotos.count<11)
{
UIImage *image = [UIImage imageWithCGImage:result.defaultRepresentation.fullScreenImage];
[_savedPhotos addObject:image];
}
else
{
*needToStop = YES;
}
}];
} failureBlock:^(NSError *error) {
NSLog(#"%#",error.description);
}];
The ALAssetsLibrary library will run on a separate thread. So it may take time to communicate with the UI related and other stuff.
So use -performSelectorOnMainThread:withObject:waitUntilDone: inside the ALAssetsLibrary block.
Change your code as below
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
[group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *needToStop) {
NSLog(#"%d",index);
UIImage *image = [UIImage imageWithCGImage:result.defaultRepresentation.fullScreenImage];
[self performSelectorOnMainThread:#selector(usePhotolibraryimage:) withObject:image waitUntilDone:NO];
}];
}
failureBlock:^(NSError *error) {
NSLog(#"%#",error.description);
}];
- (void)usePhotolibraryimage:(UiImage *)myImage{
//Do your all UI related and all stuff here
}
Note:Look on this issue too.

Wait for assetForURL blocks to be completed

I would like to wait this code to be executed before to continue but as these blocks are called assynchronously I don't know how to do???
NSURL *asseturl;
NSMutableArray *tmpListAsset = [[NSMutableArray alloc] init];
ALAssetsLibrary *library = [[[ALAssetsLibrary alloc] init] autorelease];
NSMutableArray *objectsToRemove = [[NSMutableArray alloc] init];
for (NSDictionary *dico in assetsList) {
asseturl = [NSURL URLWithString:[dico objectForKey:#"assetUrl"]];
NSLog(#"asset url %#", asseturl);
// Try to load asset at mediaURL
[library assetForURL:asseturl resultBlock:^(ALAsset *asset) {
// If asset doesn't exists
if (!asset){
[objectsToRemove addObject:dico];
}else{
[tmpListAsset addObject:[asseturl absoluteString]];
NSLog(#"tmpListAsset : %#", tmpListAsset);
}
} failureBlock:^(NSError *error) {
// Type your code here for failure (when user doesn't allow location in your app)
}];
}
GCD semaphore approach:
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
for (NSURL *url in self.assetUrls) {
dispatch_async(queue, ^{
[library assetForURL:url resultBlock:^(ALAsset *asset) {
[self.assets addObject:asset];
dispatch_semaphore_signal(sema);
} failureBlock:^(NSError *error) {
dispatch_semaphore_signal(sema);
}];
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
dispatch_release(sema);
/* Check out ALAssets */
NSLog(#"%#", self.assets);
The solution is here
http://omegadelta.net/2011/05/10/how-to-wait-for-ios-methods-with-completion-blocks-to-finish/
Note that assetForURL:resultBlock:failureBlock: will stuck if the main thread is waiting without RunLoop running. This is alternative ( cleaner :-) ) solution:
#import <libkern/OSAtomic.h>
...
ALAssetsLibrary *library;
NSMutableArray *assets;
...
__block int32_t counter = 0;
for (NSURL *url in urls) {
OSAtomicIncrement32(&counter);
[library assetForURL:url resultBlock:^(ALAsset *asset) {
if (asset)
[assets addObject:asset];
OSAtomicDecrement32(&counter);
} failureBlock:^(NSError *error) {
OSAtomicDecrement32(&counter);
}];
}
while (counter > 0) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
}
The easiest thing to do is to move your code to inside (at the end of) the resultBlock or the failureBlock. That way, your code will run in the correct order, and you will also retain asynchronous behaviour.
This is an easy way to do it. Maybe not as elegant as using GCD but it should get the job done ... This will make your method blocking instead of non-blocking.
__block BOOL isFinished = NO;
NSURL *asseturl;
NSMutableArray *tmpListAsset = [[NSMutableArray alloc] init];
ALAssetsLibrary *library = [[[ALAssetsLibrary alloc] init];
NSMutableArray *objectsToRemove = [[NSMutableArray alloc] init];
for (NSDictionary *dico in assetsList) {
asseturl = [NSURL URLWithString:[dico objectForKey:#"assetUrl"]];
NSLog(#"asset url %#", asseturl);
// Try to load asset at mediaURL
[library assetForURL:asseturl resultBlock:^(ALAsset *asset) {
// If asset doesn't exists
if (!asset){
[objectsToRemove addObject:dico];
}else{
[tmpListAsset addObject:[asseturl absoluteString]];
NSLog(#"tmpListAsset : %#", tmpListAsset);
}
if (objectsToRemove.count + tmpListAsset.count == assetsList.count) {
isFinished = YES;
}
} failureBlock:^(NSError *error) {
// Type your code here for failure (when user doesn't allow location in your app)
isFinished = YES;
}];
}
while (!isFinished) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01f]];
}

ALAssetsLibrary enumerateGroupsWithTypes: - Thread synchronization

I'm using [ALAssetsLibrary enumerateGroupsWithTypes:] to store the ALAssets in an array. As this is an asynchronous operation, I need to wait for it to finish before continuing my work.
I read Cocoa thread synchronisation when using [ALAssetsLibrary enumerateGroupsWithTypes:] and tried the recommended NSConditionLock. However, the blocks are always performed in the main thread, thus if I wait using the conditionlock, the main thread is blocked and the blocks won't get executed -> I'm stuck.
I even tried running the method loadAssets on a new thread, but still the blocks get executed on the main thread.
I can't find a way to actually wait for the enumeration to finish. Is there a way to force the blocks to a different thread than the main thread or anything else I can do?
Here's the code:
- (void)loadAssets
{
assets = [NSMutableArray array];
NSConditionLock *threadLock = [[NSConditionLock alloc] initWithCondition:THREADRUNNING];
void (^assetEnumerator)(ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop)
{
if(result != nil)
{
[assets addObject:result];
}
};
void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop)
{
if(group != nil)
{
[group enumerateAssetsUsingBlock:assetEnumerator];
}
[threadLock lock];
[threadLock unlockWithCondition:THREADFINISHED];
};
void (^assetFailureBlock)(NSError *) = ^(NSError *error)
{
[threadLock lock];
[threadLock unlockWithCondition:THREADFINISHED];
};
ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
[assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:assetGroupEnumerator failureBlock:assetFailureBlock];
[threadLock lockWhenCondition:THREADFINISHED];
[threadLock unlock];
[assetsLibrary release];
[threadLock release];
}
you are killing your assetsLibrary object before it finished to enumrate the objects.
move it to your .h file and release it in dealloc.
I know this thread is probably dead, but I'm answering it because this is where I landed by Googling
The trick is to lock your background thread until the enumeration yields a nil-group. This category is one example of how to use it, you can use the category method as a drop-in replacement of the ALAssetsLibrary enumeration method.
#implementation ALAssetsLibrary (EEEConcurrency)
- (NSUInteger)eee_enumerateGroupsLockedWithTypes:(ALAssetsGroupType)types
usingBlock:(ALAssetsLibraryGroupsEnumerationResultsBlock)enumerationBlock
failureBlock:(ALAssetsLibraryAccessFailureBlock)failureBlock
{
NSAssert(![NSThread isMainThread], #"This would create a deadlock (main thread waiting for main thread to complete)");
enum
{
EEEAssetsLibraryDone,
EEEAssetsLibraryBusy
};
NSConditionLock *assetsLibraryConditionLock = [[NSConditionLock alloc] initWithCondition:EEEAssetsLibraryBusy];
__block NSUInteger numberOfGroups = 0;
[self enumerateGroupsWithTypes:types
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
enumerationBlock(group, stop);
if (group) numberOfGroups++;
if (!group || *stop)
{
[assetsLibraryConditionLock lock];
[assetsLibraryConditionLock unlockWithCondition:EEEAssetsLibraryDone];
}
}
failureBlock:^(NSError *error) {
failureBlock(error);
[assetsLibraryConditionLock lock];
[assetsLibraryConditionLock unlockWithCondition:EEEAssetsLibraryDone];
}];
[assetsLibraryConditionLock lockWhenCondition:EEEAssetsLibraryDone];
[assetsLibraryConditionLock unlock];
return numberOfGroups;
}
#end
Download the category at https://gist.github.com/epologee/8890692
This code chunk should work for you -->
ALAssetsLibrary *assetsLib = [[ALAssetsLibrary alloc] init];
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
__block int numberOfGroups = 0;
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[assetsLib enumerateGroupsWithTypes:ALAssetsGroupAlbum usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if (group) {
numberOfGroups++;
}
else {
dispatch_semaphore_signal(sema);
}
} failureBlock:^(NSError *error) {
NSLog(#"enumerateGroupsWithTypes failure %#", [error localizedDescription]);
dispatch_semaphore_signal(sema);
}];
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
NSLog( #"number of groups is: %d", numGroups);
Although instead of DISPATCH_TIME_FOREVER you may want to make the time one second from now
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
_assetsLibrary = [[ALAssetsLibrary alloc] init];
ALAssetsLibraryGroupsEnumerationResultsBlock listGroupBlock = ^(ALAssetsGroup *group, BOOL *stop) {
if (group)
{
if (((NSString *)[group valueForProperty:ALAssetsGroupPropertyType]).intValue == ALAssetsGroupAlbum)
{
[albumSettingsList addObject:group];
} else {
dispatch_semaphore_signal(sema);
}
}
};
ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError *error) {
switch ([error code]) {
case ALAssetsLibraryAccessUserDeniedError:
case ALAssetsLibraryAccessGloballyDeniedError:
break;
default:
break;
}
dispatch_semaphore_signal(sema);
};
NSUInteger groupTypes = ALAssetsGroupAlbum | ALAssetsGroupEvent | ALAssetsGroupFaces | ALAssetsGroupSavedPhotos;
[self.assetsLibrary enumerateGroupsWithTypes:groupTypes usingBlock:listGroupBlock failureBlock:failureBlock];
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
whenever you want to get album list synchoronos with IOS 7
Use dispatch_semaphore_t to control it
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
[assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:^(ALAssetsGroup *assetsGroup, BOOL *stop) {
if (assetsGroup) {
// Filter the assets group
[assetsGroup setAssetsFilter:[ALAssetsFilter allAssets]];
// Add assets group
if (assetsGroup.numberOfAssets > 0) {
// Add assets group
DNAlbum *album = [DNAlbum albumWithAssetGroup:assetsGroup];
[albumArray addObject:album];
}
}
if (*stop || !assetsGroup) {
dispatch_semaphore_signal(sem);
}
} failureBlock:^(NSError *error) {
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);