Hieicker
Hieicker

Reputation: 595

Retrieve images inside the device finish all the memory resources and the app crash

I have implemented a method that retrieve the images inside my device using the alasset library. It works perfectly with the newest devices like iPhone 4, iphone 4s and iPad, but with an old iPhone 3GS the application some seconds crash. I now that probably is because iPhone 3gs has less resources in confront to iPhone 5 or iPad, but i want that my application works also on it. The problem is that the iPhone 3gs has in the gallery more than 1700 photos and if i read the assets it give me the warning message “Received memory warning.” after approximately around the 40th image. After the application crash. This is the method that i’m using. I need to understand what i’m doing wrong and how can i modify my code. Is there the possibility that the NSConditionLock doesn’t release every asset after that it has read but it pass all the 1700 images before release the resources?

-(NSString *) getPhotos{
enum { WDASSETURL_PENDINGREADS = 1, WDASSETURL_ALLFINISHED = 0};
NSMutableArray *idList = [[NSMutableArray alloc] init]; //create the array that will contains the informations about the images that we want return like an xml
XMLWriter* xmlWriter = [[XMLWriter alloc]init];
__block NSString *xmlList; //xmlList is the string that we will return to the client
NSConditionLock * assetsReadLock = [[NSConditionLock alloc] initWithCondition:WDASSETURL_PENDINGREADS]; //this is the condition for lock the images when we need to find the informations about the images.
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; //declare the library that give to us the access to the media info
    //NSString *description = [[NSString alloc] init];
    __block UIDevice *aDevice = [UIDevice currentDevice];
    [library enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
        __block NSString *systemVersion = [[NSString alloc] init];
        if (group) {
            NSString *album = [group valueForProperty:ALAssetsGroupPropertyName]; //take the current name of the selected album
            [group setAssetsFilter:[ALAssetsFilter allPhotos]]; //search for the photos
            [group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop){
                ALAssetRepresentation *representation = [asset defaultRepresentation];
                NSDictionary *metadata = [representation metadata];
                if (asset){ //when a photo is found
                    NSString *description = [asset description]; //contains the main informations about the images. It doesn't contains the TIFF informations.
                    systemVersion = [aDevice systemVersion];
                    NSRange pathRange = [systemVersion rangeOfString:@"5."];
                    if(pathRange.location == 0){
                        NSString *path = [description substringWithRange:NSMakeRange(50, [description length]-54)]; //take the correct asset removing the unnecessary words
                        [idList addObject:path]; //add the element to the list
                    } else {
                        NSString *path = [description substringWithRange:NSMakeRange(27, [description length]-27)]; //take the correct asset removing the unnecessary words
                        [idList addObject:path]; //add the element to the list
                    }
                }
            }];
        }
        if (group == nil){ //it mean that he has passed all images
            if ([idList count] != 0){
                NSString *finalNames = [[NSString alloc] init];
                [xmlWriter writeStartDocumentWithEncodingAndVersion:@"UTF-8" version:@"1.0"]; //start the xml document
                [xmlWriter writeStartElement:@"Data"]; //Write the first tag

                    int z = 0;
                    for (z = 0; z <= [idList count]-1; z++){
                            [xmlWriter writeStartElement:@"Photo"];
                            [xmlWriter writeAttribute:@"Id" value:[idList objectAtIndex:z]]; //write the id, in this case is the path
                            [xmlWriter writeEndElement:@"Photo"];
                        }
                    }
                [xmlWriter writeEndElement:@"Data"]; //close the first tag
                [xmlWriter writeEndDocument]; //close the document
                xmlList = [xmlWriter toString];
                [assetsReadLock unlockWithCondition:WDASSETURL_ALLFINISHED];
            } else {
                [xmlWriter writeStartDocumentWithEncodingAndVersion:@"UTF-8" version:@"1.0"]; //start the xml document
                [xmlWriter writeStartElement:@"Data"]; //Write the first tag
                [xmlWriter writeAttribute:@"Message" value:@"No images founded"];
                [xmlWriter writeEndElement:@"Data"]; //close the first tag
                [xmlWriter writeEndDocument]; //close the document
                xmlList = [xmlWriter toString];
                [assetsReadLock unlockWithCondition:WDASSETURL_ALLFINISHED];
            }
        }
    } failureBlock:^(NSError *error) {
        NSLog(@"error enumerating AssetLibrary groups %@\n", error);
        [assetsReadLock lock];
        [assetsReadLock unlockWithCondition:WDASSETURL_ALLFINISHED];
    }];

[assetsReadLock lockWhenCondition:WDASSETURL_ALLFINISHED];
[assetsReadLock unlock];
return xmlList;

}

UPDATE: The console log is showing this:

Nov 21 11:12:00 T50 installd[378] <Error>: 0x2ffbc000 handle_install: Install of "/var/mobile/Media/PublicStaging/DiLand Kiosk Connect.app" requested by mobile_installation_proxy
Nov 21 11:12:00 T50 com.apple.launchd[1] (com.apple.aslmanager) <Notice>: (com.apple.aslmanager) Throttling respawn: Will start in 1 seconds
Nov 21 11:12:00 T50 installd[378] <Error>: 0x2ffbc000 MobileInstallationInstall_Server: Installing app com.fitengineering.DiLandKioskConnect
Nov 21 11:12:01 T50 installd[378] <Error>: Nov 21 11:12:01  SecTrustEvaluate  [leaf CriticalExtensions IssuerCommonName]
Nov 21 11:12:02 T50 SpringBoard[66] <Warning>: Killing com.fitengineering.DiLandKioskConnect for termination assertion
Nov 21 11:12:04 T50 installd[378] <Error>: 0x2ffbc000 MobileInstallationInstall_Server: Staging: 0.03s; Waiting: 0.00s; Installation: 2.75s; LS Sync: 0.81s; Overall: 3.62s
Nov 21 11:12:04 T50 lsd[410] <Warning>: updating identifier store
Nov 21 11:12:04 T50 lsd[410] <Warning>: Attempting to store identifiers file
Nov 21 11:12:04 T50 mobile_house_arrest[415] <Error>: Max open files: 78
Nov 21 11:12:04 T50 com.apple.launchd[1] (com.apple.aslmanager) <Notice>: (com.apple.aslmanager) Throttling respawn: Will start in 7 seconds
Nov 21 11:12:05 T50 mobile_house_arrest[416] <Error>: Max open files: 78
Nov 21 11:12:05 T50 com.apple.debugserver-199[417] <Warning>: debugserver-199 for armv7.
Nov 21 11:12:05 T50 com.apple.debugserver-199[417] <Warning>: Connecting to com.apple.debugserver service...
Nov 21 11:12:05 T50 kernel[0] <Debug>: lockbot[406] Builtin profile: debugserver (sandbox)
Nov 21 11:12:05 T50 com.apple.debugserver-199[417] <Warning>: Got a connection, waiting for process information for launching or attaching.
Nov 21 11:12:05 T50 com.apple.launchd[1] (UIKitApplication:com.fitengineering.DiLandKioskConnect[0x68e9][419]) <Warning>: (UIKitApplication:com.fitengineering.DiLandKioskConnect[0x68e9]) Spawned and waiting for the debugger to attach before continuing...
Nov 21 11:12:05 T50 com.apple.debugserver-199[417] <Warning>: Got a connection, waiting for debugger instructions.
Nov 21 11:12:06 T50 kernel[0] <Debug>: launchd[419] Builtin profile: container (sandbox)
Nov 21 11:12:06 T50 kernel[0] <Debug>: launchd[419] Container: /private/var/mobile/Applications/246DC61D-8D40-4713-A73B-C816EBCDEE6A (sandbox)
Nov 21 11:12:06 T50 mobile_house_arrest[420] <Error>: Max open files: 78
Nov 21 11:12:06 T50 ReportCrash[422] <Notice>: Not saving Jetsam log because no data from the kernel.
Nov 21 11:12:06 T50 mobile_house_arrest[421] <Error>: Max open files: 78
Nov 21 11:12:07 T50 mobile_house_arrest[423] <Error>: Max open files: 78
Nov 21 11:12:07 T50 com.apple.launchd[1] (com.apple.aslmanager) <Notice>: (com.apple.aslmanager) Throttling respawn: Will start in 4 seconds
Nov 21 11:12:07 T50 mobile_house_arrest[425] <Error>: Max open files: 78
Nov 21 11:12:08 T50 mobile_house_arrest[426] <Error>: Max open files: 78
Nov 21 11:12:12 T50 DiLand Kiosk Connect[419] <Warning>: Reachability Flag Status: -R -----l- networkStatusForFlags
Nov 21 11:12:23 T50 lockdownd[43] <Notice>: 2ff51000 spawn_and_handle_checkin: Timeout on socket /var/run/lockdown/checkin.120 waiting for com.apple.crashreportmover to checkin for Xcode. spawn=1385028728 select=1385028728 now=1385028743
Nov 21 11:12:23 T50 ReportCrash[428] <Error>: libMobileGestalt copySystemVersionDictionaryValue: Could not lookup ReleaseType from system version dictionary
Nov 21 11:12:23 T50 ReportCrash[428] <Warning>: Not internal build
Nov 21 11:12:24 T50 ReportCrash[428] <Notice>: Saved crashreport to /Library/Logs/CrashReporter/stacks-2013-11-21-111224.plist using uid: 0 gid: 0, synthetic_euid: 0 egid: 0
Nov 21 11:12:24 T50 ReportCrash[428] <Error>: libMobileGestalt copySystemVersionDictionaryValue: Could not lookup ReleaseType from system version dictionary
Nov 21 11:12:24 T50 DiLand Kiosk Connect[419] <Warning>: PATH assets-library://asset/asset.JPG?id=3B1FF4C6-55FE-44C5-9D09-C3316D5794D1&ext=JPG
LIST OF ASSETS HERE
Nov 21 11:12:28 T50 DiLand Kiosk Connect[419] <Warning>: Received memory warning.
Nov 21 11:12:28 T50 UserEventAgent[13] <Notice>: jetsam: kernel termination snapshot being created
Nov 21 11:12:28 T50 com.apple.launchd[1] (com.apple.accountsd[374]) <Notice>: (com.apple.accountsd) Idle-exit job was jettisoned. Will bypass throttle interval for next on-demand launch.
Nov 21 11:12:28 T50 com.apple.launchd[1] (com.apple.accountsd[374]) <Notice>: (com.apple.accountsd) Exited: Killed: 9
Nov 21 11:12:28 T50 com.apple.launchd[1] (com.apple.assetsd[365]) <Notice>: (com.apple.assetsd) Idle-exit job was jettisoned. Will bypass throttle interval for next on-demand launch.
Nov 21 11:12:28 T50 com.apple.launchd[1] (com.apple.assetsd[365]) <Notice>: (com.apple.assetsd) Exited: Killed: 9
Nov 21 11:12:28 T50 DiLand Kiosk Connect[419] <Warning>: Received error from assetsd.
Nov 21 11:12:28 T50 SpringBoard[66] <Warning>: Received memory warning.
Nov 21 11:12:29 T50 ReportCrash[432] <Error>: libMobileGestalt copySystemVersionDictionaryValue: Could not lookup ReleaseType from system version dictionary
Nov 21 11:12:29 T50 ReportCrash[432] <Notice>: Not saving suspended-only Jetsam log because already dumped today.
Nov 21 11:12:30 T50 MobileMail[367] <Warning>: Received memory warning.
Nov 21 11:12:31 T50 DiLand Kiosk Connect[419] <Warning>: PATH assets-library://asset/asset.JPG?id=DE6660FE-7242-4449-96A9-4D718B0D0AA4&ext=JPG
Nov 21 11:12:31 T50 UserEventAgent[13] <Notice>: jetsam: kernel termination snapshot being created
Nov 21 11:12:31 T50 com.apple.launchd[1] (com.apple.assetsd[433]) <Notice>: (com.apple.assetsd) Idle-exit job was jettisoned. Will bypass throttle interval for next on-demand launch.
Nov 21 11:12:31 T50 com.apple.launchd[1] (com.apple.assetsd[433]) <Notice>: (com.apple.assetsd) Exited: Killed: 9
Nov 21 11:12:31 T50 DiLand Kiosk Connect[419] <Warning>: Received error from assetsd.
Nov 21 11:12:31 T50 MobilePhone[369] <Warning>: Received memory warning.
Nov 21 11:12:45 T50 com.apple.debugserver-199[417] <Warning>: 1 +0.000000 sec [01a1/1303]: error: ::read ( 5, 0x2ff509fc, 18446744069414585344 ) => -1 err = Bad file descriptor (0x00000009)
Nov 21 11:12:45 T50 com.apple.launchd[1] (UIKitApplication:com.apple.mobilemail[0x409e][367]) <Notice>: (UIKitApplication:com.apple.mobilemail[0x409e]) Exited: Killed: 9
Nov 21 11:12:45 T50 com.apple.launchd[1] (UIKitApplication:com.apple.mobilephone[0x8c42][369]) <Notice>: (UIKitApplication:com.apple.mobilephone[0x8c42]) Exited: Killed: 9
Nov 21 11:12:45 T50 com.apple.launchd[1] (com.apple.tccd[371]) <Notice>: (com.apple.tccd) Exited: Killed: 9
Nov 21 11:12:45 T50 com.apple.launchd[1] (UIKitApplication:com.fitengineering.DiLandKioskConnect[0x68e9][419]) <Notice>: (UIKitApplication:com.fitengineering.DiLandKioskConnect[0x68e9]) Exited: Killed: 9
Nov 21 11:12:45 T50 backboardd[26] <Warning>: Application 'UIKitApplication:com.apple.mobilephone[0x8c42]' exited abnormally with signal 9: Killed: 9

UPDATE 2: This is the device log

Incident Identifier: 5CC39233-317D-490D-B21C-813B629F95D5
CrashReporter Key:   4911764fc74ada97463a46613032769e29097835
Hardware Model:      iPhone2,1
OS Version:          iPhone OS 6.1.3 (10B329)
Kernel version:      Darwin Kernel Version 13.0.0: Wed Feb 13 21:35:42 PST 2013; root:xnu-2107.7.55.2.2~1/RELEASE_ARM_S5L8920X
Date:                2013-11-21 11:12:23 +0100
Exception Code:      0xdeadfeed
Reason:              Timeout on socket /var/run/lockdown/checkin.120 waiting for com.apple.crashreportmover to checkin for Xcode. spawn=1385028728 select=1385028728 now=1385028743
Thermal Level:       0
Thermal Sensors:    3041 2846 3516 2799 2767 5161 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Frontmost process PID:    419
Frontmost process PID:    66
Jetsam Level:              0
Free Pages:            14798
Active Pages:           9223
Inactive Pages:         5756
Purgeable Pages:           4
Wired Pages:           12255
Speculative Pages:      8286
Throttled Pages:       14717
Busy Buffer Count:         0
Pages Wanted:              0
Pages Reclaimed:           0

Process 0 info:
resident memory bytes:  33886208
page faults:                382
page-ins:                     0
copy-on-write faults:         0
user   time in task:  1109.081110 seconds
system time in task:     0.000000 seconds

Process 0 kernel_task threads:
thread 0x1 TH_WAIT|TH_UNINT 0x803282e0
thread priority:          92
thread sched flags:     none
kernel cont 800622ed
user   time in thread:     2.045010 seconds
system time in thread:     0.000000 seconds
… Many Threads here …
thread 0x132c TH_WAIT|TH_UNINT 0x98e5d79c
thread priority:          81
thread sched flags:     none
kernel cont 802582fd
user   time in thread:     0.000028 seconds
system time in thread:     0.000000 seconds

Process 1 info:
resident memory bytes:  614400
page faults:              16083
page-ins:                  1153
copy-on-write faults:      8901
user   time in task:     5.258988 seconds
system time in task:     0.000000 seconds

Process 1 binary images:
0x2fe56000 <280610df5ed43ec7aa00629a27009302>
0x2d000 <10ff8d45040239d1b479cddf29e6b50e>

Process 1 launchd threads:
thread 0xfe TH_WAIT 0
thread priority:          31
thread sched flags:     none
kernel cont 800104f1
user 0x3ac23eb4 0x3ac2404d 0x3ac7f85b 0x3ac7f943 0x320f7 0x3063f 0x3ab6db20
user   time in thread:     4.761893 seconds
system time in thread:     0.000000 seconds

… HERE THERE ARE MANY OTHER PROCESS THAT I HAVE REMOVED FOR REDUCE THE DIMENSION OF THE LOG

Process 428 binary images:
0x2fe3a000 <280610df5ed43ec7aa00629a27009302>
0x6c000 <68e323272a9d37c58ba4cdf1279764c4>

Process 428 ReportCrash threads:
thread 0x267c TH_WAIT 0x803020d4
thread priority:          30
thread sched flags:     none
kernel cont 80027845
user 0x3ac346a4 0x3ab923d3 0x3abf2deb 0x76063 0x3ab6db20
user   time in thread:     0.031530 seconds
system time in thread:     0.000000 seconds
thread 0x267d TH_WAIT 0
thread priority:          33
thread sched flags:     none
kernel cont 801d1795
user 0x3ac24648 0x3ab5d4f1 0x3ab4fdf8 0
user   time in thread:     0.000822 seconds
system time in thread:     0.000000 seconds
thread 0x267e TH_WAIT 0x9cd64900
thread priority:          29
thread sched flags:     none
kernel cont 802196cd
user 0x3ac34d98 0x3ab82cfb 0x3ab82a16 0x3ab828a4
user   time in thread:     0.001473 seconds
system time in thread:     0.000000 seconds
thread 0x2680 TH_RUN 0
thread priority:          24
thread sched flags:     none
kernel 0x80024ea1
user 0x3ac34bd8 0x7a365 0x75677 0x6d76f 0x6d877 0x3ac325a7 0x74625 0x3ab8d311 0x3ab8d1d8
user   time in thread:     0.083545 seconds
system time in thread:     0.000000 seconds
thread 0x2681 TH_WAIT 0
thread priority:          31
thread sched flags:     none
kernel cont 800104f1
user 0x3ac23eb4 0x3ac2404d 0x3ac32541 0x74625 0x3ab8d311 0x3ab8d1d8
user   time in thread:     0.000125 seconds
system time in thread:     0.000000 seconds
thread 0x2682 TH_WAIT 0x9d0e6b40
thread priority:          29
thread sched flags:     none
kernel cont 802196cd
user 0x3ac34d98 0x3ab82cfb 0x3ab82a16 0x3ab828a4
user   time in thread:     0.000198 seconds
system time in thread:     0.000000 seconds


Global binary images:
0x319b9000  <b3cd09ef40143ad78034d6d3c9e204f2>
… AND HERE THERE ARE MANY GLOBAL BINARY IMAGES …

Thanks

Upvotes: 1

Views: 1060

Answers (1)

mbpro
mbpro

Reputation: 2490

I think this code need some improvements before further investigations, although by looking at it, it is hard to imagine, that collection of strings would take up the memory. Still, you haven't written anything about available memory at the time of testing.

  • ask yourself if you really need a lock on resources. App runs of iPhone and there is a very little probability that some other process will access photo assets at the same time you do now this app. You are surely not taking photos at the time, right? Locks do not come cheap.

  • if you need a lock, then lock the resources within async thread, not outside from the main, meaning within the block. In your case it is not really clear what you are locking anyway.

  • put __block directive in front of idList declaration

  • anyway, method enumerateGroupsWithTypes is asynchronous, so there is no need to dispatch_async anything additionally

  • have you implemented applicationDidReceiveMemoryWarning: in your UIApplicationDelegate?

  • track the crash with instruments. Enumerating method is most probably autoreleasing something, so it is possibility of zombie as well, especially because it is happening on back thread.

Let's see later, how it will perform. Try different combination.

EDIT:

OK. Let's update this code further:

  • remove __block directive from line, it is unnecessary:

    __block NSString *systemVersion = [[NSString alloc] init];

  • this is wrong, please, read the documentation further on NSString class, do not initialize NSString, just declare it:

NSString *systemVersion;

  • move __block UIDevice *aDevice = [UIDevice currentDevice]; in front of enumerateGroupsWithTypes method and block

  • this: systemVersion = [aDevice systemVersion]; is not needed inside the callout block, this is system constant. Along with declaration mentioned above.

  • insert autorelease block inside callout block

Make all those changes and test.

Upvotes: 1

Related Questions