检索设备内的图像完成所有内存资源和应用程序崩溃

时间:2013-11-05 12:13:58

标签: objective-c image

我已经实现了一个使用alasset库检索设备内部图像的方法。它与iPhone 4,iphone 4s和iPad等最新设备完美配合,但使用旧版iPhone 3GS,应用程序会在几秒钟内崩溃。我现在可能是因为iPhone 3gs在面对iPhone 5或iPad时拥有的资源较少,但我希望我的应用程序也适用于它。问题是iPhone 3gs在画廊中有超过1700张照片,如果我阅读资产,它会在大约第40张图像后给我发出警告信息“收到内存警告”。应用程序崩溃后。这是我正在使用的方法。我需要了解我做错了什么以及如何修改我的代码。是否有可能NSConditionLock在读取之后不会释放所有资产,但在释放资源之前它会传递所有1700个图像?

-(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;

}

更新: 控制台日志显示如下:

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

更新2: 这是设备日志

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 …

由于

1 个答案:

答案 0 :(得分:1)

我认为这段代码在进一步调查之前需要一些改进,尽管通过观察它,很难想象,字符串的集合会占用内存。尽管如此,在测试时你还没有写过有关可用内存的任何内容。

  • 问问自己是否确实需要锁定资源。应用程序运行iPhone,其他一些进程在您现在使用此应用程序的同时访问照片资产的可能性很小。你当然不会拍照,对吧?锁不便宜。

  • 如果需要锁定,则将资源锁定在异步线程内,而不是在主外部,即在块内。在你的情况下,你还不清楚自己锁定了什么。

  • 将__block指令放在idList声明

  • 之前
  • 无论如何,方法enumerateGroupsWithTypes是异步的,所以不需要另外调度任何东西

  • 你在UIApplicationDelegate中实现了applicationDidReceiveMemoryWarning吗?

  • 使用乐器跟踪坠机事故。枚举方法很可能是自动释放的东西,所以它也有僵尸的可能性,特别是因为它发生在后台线程上。

让我们稍后看看它将如何表现。尝试不同的组合。

编辑:

行。让我们进一步更新此代码:

  • 从行中删除__block指令,这是不必要的:

    __阻止NSString * systemVersion = [[NSString alloc] init];

  • 这是错误的,请在NSString类上进一步阅读文档,不要初始化NSString,只需声明它:

NSString * systemVersion;

  • move __block UIDevice * aDevice = [UIDevice currentDevice];在enumerateGroupsWithTypes方法和块

  • 之前
  • 这个:systemVersion = [aDevice systemVersion];在callout块中不需要,这是系统常量。以及上面提到的声明。

  • 在callout block中插入autorelease块

进行所有这些更改并进行测试。