使用iOS的目标c,在应用程序启动时将图像预加载到内存缓存中

时间:2015-01-12 12:49:06

标签: objective-c

我遇到的问题是,试图在UITableViewCells列表中显示缩略图。我有200个缩略图要显示。

我的应用程序从远程服务器下载图像的zip文件,将内容解压缩到NSDocumentDirectory中。更新后,每周发生一次,然后应用程序使用[UIImage imageWithContentsOfFile:]显示缩略图 有一次,我知道这已被缓存,我使用[UIImage imageNamed:]

显示缩略图

我的问题是当我使用时显示200个缩略图 [UIImage imageWithContentsOfFile:]在更新后的第一个显示事件中,应用程序有时会在几分钟后冻结,并说太多图像文件已打开。

ImageIO:CGImageRead_mapData' open'失败' / Users / cdesign / Library / Application Support / iPhone Simulator / 6.1 / Applications / B458A3F5-5B21-49CD-B4D8-17E5189678FA / Documents / 91.png' 错误= 24(打开的文件太多)

一旦图像缓存在内存中,就不会发生这种情况。

然后,当我尝试点击UITableViewCell进入我的' DetailController'时,我收到以下错误:

由于未捕获的异常终止应用程序' NSInternalInconsistencyException',原因:'无法在捆绑中加载NIB:' NSBundle(已加载)'名字' 9ka-eC-wSa-view-LRp-aI-LGN'和目录' MainStoryboard.storyboardc'' ***第一次抛出调用堆栈: (0x1bd0012 0x1473e7e 0x1bcfdeb 0x5d3ef9 0x4987e7 0x498dc8 0x5e728e 0x498ff8 0x499232 0x4994da 0x4b08e5 0x4b09cb 0x4b0c76 0x4b0d71 0x4b189b 0x4b1e93 0x4b1a88 0x80de63 0x7ffb99 0x7ffc14 0x467249 0x4674ed 0xe715b3 0x1b8f376 0x1b8ee06 0x1b76a82 0x1b75f44 0x1b75e1b 0x16ef7e3 0x16ef668 0x3b7ffc 0x2a1d 0x2945) libc ++ abi.dylib:terminate调用抛出异常

这很奇怪,因为我没有名为' MainStoryboard.storyboardc'的文件。 我的应用没有本地化。我的项目甚至没有' en.lproj'夹。我只有'MainStoryboard.storyboard'在根。

我不确定2错误是否相关。或者,如果第二个错误是第一个错误。这表明我的图片没有问题?

我必须说,当我测试我的应用时,使用修改过的' getImage'只返回缓存图像的方法,第一个错误消失,但第二个错误,关于' MainStoryboard.storyboard'仍然会发生,偶尔,如果我让应用程序闲置超过几分钟,在' ListController'屏幕。

这些问题 ONLY 都发生在' ListController'屏幕。该应用程序始终成功启动,以显示' home'屏幕。在主屏幕上有一个指向' ListController'的链接。屏幕。

假设图像显示是问题,有没有办法在应用程序启动期间预加载图像以将新更新的图像从文档文件夹预加载到内存缓存中,这样我就不必使用 [UIImage imageWithContentsOfFile:]在 - (UITableViewCell *)tableView中显示图像:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath?

如果可以,我是否可以使用NSCache来实现图像预加载?

而且,如果我使用NSCache,那么使用相同名称的文件会覆盖NSCache中的条目,还是必须首先删除具有相同名称的文件?

对不起,对于先发制人的问题,请回答我最初的问题,但这可能会节省时间吗?

  1. 我的应用包含一个故事板,名为MainStoryboard.storyboard
  2. 目标设备:iPhone 5
  3. Xcode版本:4.6.3
  4. 以下是一些相关代码:

    AppDelegate.m

    - (BOOL)hasImageBeenUpdated:(NSString *)postureid{
        BOOL result = NO;
        YTAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
        if (appDelegate.imagesupdated == nil) {
            appDelegate.imagesupdated = [[NSMutableArray alloc] init];
        }
        NSString *imageid = [NSString string];
        for (int i = 0; i < appDelegate.imagesupdated.count; i++) {
            imageid = [appDelegate.imagesupdated objectAtIndex:i];
            if ([imageid isEqualToString: postureid]) {
                result = YES;
            }
        }
        return result;
    }
    
    
    - (UIImage *)getImage:(NSString *)postureid{
        self.nsLogsOn = YES;
        YTAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
        UIImage *result = [[UIImage alloc] init];
        UIImageView *imageview = [[UIImageView alloc] init];
        NSString *imagePath = [NSString stringWithFormat:@"%@.png",postureid];
        if (self.nsLogsOn) {
            NSLog(@"appDelegate.imagesHaveBeenDownloaded: %i",appDelegate.imagesHaveBeenDownloaded);
        }
        if(!appDelegate.imagesHaveBeenDownloaded){
            imageview.image = [UIImage imageNamed:imagePath];
            if (self.nsLogsOn) {
                NSLog(@"image cached no download: %@",imagePath);
            }
        }
        else{
            if (appDelegate.imagesupdated == nil) {
                appDelegate.imagesupdated = [[NSMutableArray alloc] init];
            }
            BOOL imageHasBeenUpdated = [self hasImageBeenUpdated:postureid];
            if(!imageHasBeenUpdated){
               imageview.image = [UIImage imageWithContentsOfFile:[[self documentsFilePath] stringByAppendingPathComponent:imagePath]];
                [appDelegate.imagesupdated addObject:postureid];
                if (self.nsLogsOn) {
                    NSLog(@"image download: %@",imagePath);
                }
            }
            else{
               imageview.image = [UIImage imageNamed:imagePath];
                if (self.nsLogsOn) {
                    NSLog(@"image cached download: %@",imagePath);
                }
            }
        }
        if(imageview.image==nil){
            imageview.image = [UIImage imageWithContentsOfFile:[[self documentsFilePath] stringByAppendingPathComponent:imagePath]];
            if (self.nsLogsOn) {
                NSLog(@"image cache cleared by iOS: %@",imagePath);
            }
        }
        if(imageview.image==nil){
            imageview.image = [UIImage imageNamed:@"logo-lotus-imageview-white-c.png"];
            if (self.nsLogsOn) {
                NSLog(@"image cannot be found: %@",imagePath);
            }
        }
        result = imageview.image;    
        return result;
    }
    

    ListController.m

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return [keys count];
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        NSString *key = [keys objectAtIndex:section];
        NSArray *nameSection = [posturegroups objectForKey:key];
        return [nameSection count];
    }
    
    - (NSString *)tableView:(UITableView *)tableView
    titleForHeaderInSection:(NSInteger)section {
        NSString *key = [keys objectAtIndex:section];
        return [key capitalizedString];
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        NSString *identifier = @"plainCell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
        NSString *key = [keys objectAtIndex:indexPath.section];
        NSArray *nameSection = [posturegroups objectForKey:key];
        YTPosture *thePosture = [nameSection objectAtIndex:indexPath.row];
        YTAppDelegate *appDelegate = [[YTAppDelegate alloc] init];    
        UIImageView *imageview = (UIImageView *)[cell viewWithTag:3];
        imageview.image = [appDelegate getImage:thePosture.postureid];
        imageview.backgroundColor = [appDelegate defaultColor];
        UILabel *cellLabel1 = (UILabel *)[cell viewWithTag:1];
        NSString *aStr = [NSString string];
        NSString *bStr = [NSString string];
        NSString *title = [NSString string];
        if([selection valueForKey:@"symptomExists"]){
            aStr = [NSString stringWithFormat:@"%@ ",thePosture.memberOrder];
            bStr = thePosture.title;
            title = [aStr stringByAppendingString:bStr];
        }
        else{
            title = thePosture.title;
        }
        cellLabel1.text = title;
        UILabel *cellLabel2 = (UILabel *)[cell viewWithTag:2];
        cellLabel2.text = thePosture.sanskritTransliteration;
        YTKeyController *keyController = [[YTKeyController alloc] init];
        NSMutableArray *branch = [keyController compileData];
        NSString *branchid = thePosture.branchid;
        NSString *list = @"1.0,1.0,1.0";
        NSArray *listItems = [list componentsSeparatedByString:@","];    
        for (int i = 0; i < [branch count]; i++) {
            YTBranch *theBranch = [branch objectAtIndex:i];
            if ([branchid isEqualToString:theBranch.branchid]) {
                list = theBranch.key;
                listItems = [list componentsSeparatedByString:@","];
                break;
            }
        }    
        [cell setBackgroundColor:[UIColor colorWithRed:[[listItems objectAtIndex:0] floatValue] green:[[listItems objectAtIndex:1] floatValue] blue:[[listItems objectAtIndex:2] floatValue] alpha:1]];
        return cell;
    }
    
    #pragma mark - Table view delegate
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        // Navigation logic may go here. Create and push another view controller.
        /*
         DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:@"Nib name" bundle:nil];
         // ...
         // Pass the selected object to the new view controller.
         [self.navigationController pushViewController:detailViewController animated:YES];
         */
    }
    
    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
        UIViewController *destination = segue.destinationViewController;
        if ([destination respondsToSelector:@selector(setDelegate:)]) {
            [destination setValue:self forKey:@"delegate"];
        }
        if ([destination respondsToSelector:@selector(setSelection:)]) {
            NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
            NSUInteger section = [indexPath section];
            NSString *key = [keys objectAtIndex:section];
            NSArray *nameSection = [posturegroups objectForKey:key];
            YTPosture *thePosture = [nameSection objectAtIndex:indexPath.row];
            id object = thePosture;
            NSDictionary *aselection = [NSDictionary dictionaryWithObjectsAndKeys:
                                       indexPath, @"indexPath",
                                       object, @"object",
                                       nil];
            [destination setValue:aselection forKey:@"selection"];
        }
    }
    

1 个答案:

答案 0 :(得分:1)

我发现了问题所在。我觉得有点尴尬!

第一点是&#39; MainStoryboard.storyboardc&#39;意在存在。 &#39; c&#39;最后代表&#39; MainStoryboard.storyboard&#39;的编译版本。

好吧,图像问题,是因为我试图调用一个方法,其中包括从下面的方法中编译SQLite语句:

  • (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

另外,我还在调用另一种方法,该方法在同一方法中循环了大约200个项目。

实际上,这两个例程正在为滚动到视图的每个UITableViewCell运行。

这两个问题是崩溃和烧毁系统。

一旦我删除了这些问题,我决定使用[UIImage imageWithContentsOfFile]调用图像,没有任何问题。事实上,&#39; ListController&#39;现在它有大约200个缩略图,它像丝绸一样滚动。

我觉得自己是浪费时间的白痴。最明确的是,我从中学到了很多教训。我需要调试&amp;更彻底地检查,并考虑代码的每一行及其编写的上下文。事实上,我已经了解到,加载到上述方法中的唯一信息应该是已经编入索引的数据。

Champoul建议在Memory Leaks模式下使用Instruments,我是如何找到这个问题的根源的。非常感谢你的帮助...