5

Ứng dụng của tôi muốn nhận danh sách album của iphone và tất cả các ảnh trong một album nhất định.Các sự cố GCD và KVO

Trong ứng dụng tôi liệt kê các ảnh trong một album của iphone. Vì có thể có rất nhiều ảnh của một số album nhất định, xem xét hiệu suất tôi sử dụng GCD: dispatch_async. Nhưng nó luôn luôn đổ vỡ khi cập nhật ô xem bảng được gọi bởi KVO. Tôi không biết liệu tôi có sử dụng KVO hay GCD theo cách sai hay không.

Bây giờ, tôi sử dụng performSelectorInBackground: thay thế dispatch_async. Bây giờ ứng dụng không bị lỗi nhưng hiệu suất của ứng dụng kém: tiêu đề của ô sẽ chỉ được hiển thị khi bạn chạm vào nó hoặc cuộn bảng xem khi có nhiều ảnh. Nói cách khác, chủ đề chính phải bị chặn.

Được đính kèm là mã và mã lõi nằm trong AlbumListViewController.m.

Có ai giúp tôi kiểm tra không?

Tôi chỉ muốn biết: 1 lý do tại sao ứng dụng bị lỗi nếu sử dụng dispatch_async 2 cách tôi có thể cải thiện hiệu suất trong trường hợp có nhiều ảnh.

cảm ơn.

Dưới đây là Mã của tôi:

 
// 
// RootViewController.h 
// AlbumDemo 


#import 

@interface RootViewController : UITableViewController { 
    NSMutableArray *_listArray; 
} 

@property (nonatomic, retain) NSMutableArray *listArray; 

@end 


// RootViewController.m 


#import "RootViewController.h" 
#import 
#import "AlbumListViewController.h" 
NSString *thumnail = @"thumnail"; 
NSString *albumName = @"albumName"; 
NSString *albumNum = @"albumNum"; 
NSString *albumGroup = @"albumGroup"; 
@implementation RootViewController 
@synthesize listArray = _listArray; 

#pragma - 
#pragma Function 
- (void)setUp 
{ 
    _listArray = [[NSMutableArray alloc] initWithCapacity:1]; 
    self.title = @"Albums"; 
} 
- (void)fetchAlbumList 
{ 
    ALAssetsLibrary *assetLib = [[[ALAssetsLibrary alloc] init] autorelease]; 
    ALAssetsFilter *fileter = [ALAssetsFilter allPhotos]; 
    [assetLib enumerateGroupsWithTypes:ALAssetsGroupAll 
          usingBlock:^(ALAssetsGroup *group, BOOL *stop) 
    { 
     if (group) 
     { 
      [group setAssetsFilter:fileter]; 
      NSString *_groupName = [group valueForProperty:ALAssetsGroupPropertyName]; 
      NSNumber *_groupNum = [NSNumber numberWithInteger:[group numberOfAssets]]; 
      UIImage *_groupImage = [UIImage imageWithCGImage:[group posterImage]]; 

      NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:_groupName,albumName,_groupNum,albumNum,_groupImage,thumnail,group,albumGroup, nil]; 

      [_listArray addObject:dic]; 
      [self.tableView reloadData]; 

     } 
     else 
     { 
      NSLog(@"_listArray :%@",_listArray); 
     } 

    } 
          failureBlock:^(NSError *error) 
    { 
     NSLog(@"Error: %@", error);; 
    } 
    ]; 

} 
#pragma - 
#pragma ViewController lift cycle 
- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    [self setUp]; 
    [self fetchAlbumList]; 

} 

- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:animated]; 
} 

- (void)viewDidAppear:(BOOL)animated 
{ 
    [super viewDidAppear:animated]; 
} 

- (void)viewWillDisappear:(BOOL)animated 
{ 
    [super viewWillDisappear:animated]; 
} 

- (void)viewDidDisappear:(BOOL)animated 
{ 
    [super viewDidDisappear:animated]; 
} 

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    return 50; 
} 
// Customize the number of sections in the table view. 
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    return 1; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    return [_listArray count]; 
} 

// Customize the appearance of table view cells. 
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"Cell"; 
    UILabel *nameLab = nil; 
    UILabel *numLab = nil; 
    UIImageView *thumnailImage = nil; 

    UIFont *font = [UIFont boldSystemFontOfSize:18]; 

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
     cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 
     cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 

     thumnailImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0,50, 50)]; 
     thumnailImage.tag = 100; 
     [cell.contentView addSubview:thumnailImage]; 
     [thumnailImage release]; 


     nameLab = [[UILabel alloc] initWithFrame:CGRectMake(60, 10, 100, 30)]; 
     nameLab.tag = 200; 
     nameLab.backgroundColor = [UIColor clearColor]; 
     nameLab.font = font; 
     [cell.contentView addSubview:nameLab]; 
     [nameLab release]; 

     numLab = [[UILabel alloc] initWithFrame:CGRectMake(200, 10, 50, 30)]; 
     numLab.tag = 300; 
     numLab.backgroundColor = [UIColor clearColor]; 
     numLab.textColor = [UIColor grayColor]; 
     numLab.font = font; 
     [cell.contentView addSubview:numLab]; 
     [numLab release]; 
    } 
    else 
    { 
     thumnailImage = (UIImageView *)[cell.contentView viewWithTag:100]; 
     nameLab = (UILabel *)[cell.contentView viewWithTag:200]; 
     numLab = (UILabel *)[cell.contentView viewWithTag:300]; 
    } 

    NSDictionary *dic = [self.listArray objectAtIndex:indexPath.row]; 

    thumnailImage.image = (UIImage *)[dic valueForKey:thumnail]; 

    NSString *title = [dic valueForKey:albumName]; 
    CGSize titleSize = [title sizeWithFont:font]; 
    CGRect rect = nameLab.frame; 
    rect.size = titleSize; 
    nameLab.frame = rect; 
    nameLab.text = title; 

    rect = numLab.frame; 
    rect.origin.x = 60 + nameLab.frame.size.width + 10; 
    numLab.frame = rect; 

    numLab.text = [NSString stringWithFormat:@"(%d)",[[dic valueForKey:albumNum] intValue]]; 


    // Configure the cell. 
    return cell; 
} 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSDictionary *dic = [self.listArray objectAtIndex:indexPath.row]; 

    AlbumListViewController *viewController = [[AlbumListViewController alloc] initWithAssetGroup:[dic valueForKey:albumGroup]]; 
    [self.navigationController pushViewController:viewController animated:YES]; 
    [viewController release]; 
    [tableView deselectRowAtIndexPath:indexPath animated:YES]; 
} 

- (void)didReceiveMemoryWarning 
{ 
    // Releases the view if it doesn't have a superview. 
    [super didReceiveMemoryWarning]; 

    // Relinquish ownership any cached data, images, etc that aren't in use. 
} 

- (void)viewDidUnload 
{ 
    [super viewDidUnload]; 

    // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand. 
    // For example: self.myOutlet = nil; 
} 

- (void)dealloc 
{ 
    My_Release (_listArray); 
    [super dealloc]; 
} 

@end 


// AlbumListViewController.h 
// AlbumDemo 

#import 
#import 

@interface AlbumListViewController : UITableViewController { 
    NSMutableArray *_marr; 
    ALAssetsGroup *_assetsGroup; 
} 

@property (nonatomic, retain) NSMutableArray *list; 
@property (nonatomic, retain) ALAssetsGroup *assetsGroup; 

- (id)initWithAssetGroup:(ALAssetsGroup *)group; 
@end 

// AlbumListViewController.m 
// AlbumDemo 

#import "AlbumListViewController.h" 

@interface PhotoObj : NSObject { 
    NSString *_name; 
    UIImage *_thumbnail; 
    UIImage *_fullImage; 
} 

@property (nonatomic, copy ) NSString *name; 
@property (nonatomic, retain) UIImage *thumbnail; 
@property (nonatomic, retain) UIImage *fullImage; 
@end 

@implementation PhotoObj 
@synthesize name = _name; 
@synthesize thumbnail = _thumbnail,fullImage = _fullImage; 
- (void)dealloc 
{ 
    My_Release(_thumbnail); 
    My_Release(_fullImage); 
    My_Release(_name); 
    [super dealloc]; 
} 
@end 

@interface AlbumListViewController() 

- (NSMutableArray*)list; 
- (NSUInteger)countOfList; 
- (id)objectInListAtIndex:(NSUInteger)idx; 
- (void)insertObject:(id)anObject inListAtIndex:(NSUInteger)idx; 
- (id)objectInListAtIndex:(NSUInteger)idx; 
- (void)removeObjectFromListAtIndex:(NSUInteger)idx; 
- (void)replaceObjectInListAtIndex:(NSUInteger)idx withObject:(id)anObject; 
- (void)setList:(NSMutableArray *)_arr; 

@end 

@implementation AlbumListViewController 
@synthesize assetsGroup = _assetsGroup; 

- (id)initWithAssetGroup:(ALAssetsGroup *)group 
{ 
    self = [self initWithStyle:UITableViewStylePlain]; 
    if (self) 
    { 
     _marr = [[NSMutableArray alloc] initWithCapacity:1]; 
     self.assetsGroup = group; 
     self.tableView.delegate = self; 
     self.tableView.dataSource = self; 

    } 
    return self; 
} 

- (id)initWithStyle:(UITableViewStyle)style 
{ 
    self = [super initWithStyle:style]; 
    if (self) { 
     // Custom initialization 
    } 
    return self; 
} 

- (void)dealloc 
{ 
    My_Release(_marr); 
    My_Release(_assetsGroup); 
    [self removeObserver:self forKeyPath:@"list"]; 
    [super dealloc]; 
} 

- (void)didReceiveMemoryWarning 
{ 
    // Releases the view if it doesn't have a superview. 
    [super didReceiveMemoryWarning]; 

} 

#pragma mark - View lifecycle 
- (void)parseAssetGroup 
{ 
    [_marr removeAllObjects]; 
    [self.assetsGroup enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) { 
     if (result) 
     { 
      PhotoObj *obj = [[PhotoObj alloc] init]; 
      obj.thumbnail = [UIImage imageWithCGImage:[result thumbnail]]; 
      ALAssetRepresentation *represention = [result defaultRepresentation]; 
      obj.fullImage = [UIImage imageWithCGImage:[represention fullScreenImage]]; 
      obj.name = [[represention url] absoluteString]; 


      [self willChangeValueForKey:@"list"]; 
      [self insertObject:obj inListAtIndex:[_marr count]]; 
      [self didChangeValueForKey:@"list"]; 
      My_Release(obj); 
     } 

    }]; 

} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    [self addObserver:self forKeyPath:@"list" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:NULL]; 
    /* 
    if performSelectorInBackground, the perofrmance is poor 
    as the title of the cell will be shown in a long time and it now seems the main thread is blocked 
    */ 
    [self performSelectorInBackground:@selector(parseAssetGroup) withObject:nil]; 
    /* 
    using dispatch_async it always crashes 
    as it says the sth is wrong with the tableview update 

    */ 

// dispatch_async(dispatch_get_main_queue(), ^{ 
//  [self parseAssetGroup]; 
// }); 
} 

- (void)viewDidUnload 
{ 
    [super viewDidUnload]; 

} 

#pragma mark - Table view data source 
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    return 50; 
} 
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    // Return the number of sections. 
    return 1; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    // Return the number of rows in the section. 
    return [_marr count]; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"Cell"; 

    UIImageView *thumbNail = nil; 
    UILabel *nameLab = nil; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
     cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 
     cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 

     thumbNail = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)]; 
     thumbNail.tag = 99; 
     [cell.contentView addSubview:thumbNail]; 
     [thumbNail release]; 

     nameLab = [[UILabel alloc] initWithFrame:CGRectMake(60, 10, 240, 40)]; 
     nameLab.numberOfLines = 2; 
     nameLab.font = [UIFont systemFontOfSize:16]; 
     nameLab.tag = 199; 
     [cell.contentView addSubview:nameLab]; 
     [nameLab release]; 
    } 
    else 
    { 
     thumbNail = (UIImageView *)[cell.contentView viewWithTag:99]; 
     nameLab = (UILabel *)[cell.contentView viewWithTag:199]; 
    } 
    // Configure the cell... 
    PhotoObj *obj = [_marr objectAtIndex:indexPath.row]; 
    nameLab.text = obj.name; 
    thumbNail.image = obj.thumbnail; 

    return cell; 
} 
#pragma mark - 
- (NSUInteger)countOfList 
{ 
    return [_marr count]; 
} 
- (NSMutableArray*)list 
{ 
    return _marr; 
} 
- (void)setList:(NSMutableArray *)_arr 
{ 
    if (_marr != _arr) 
    { 
     [_marr release]; 
     _marr = _arr; 
    } 
} 

- (id)objectInListAtIndex:(NSUInteger)idx 
{ 
    return [_marr objectAtIndex:idx]; 
} 

- (void)insertObject:(id)anObject inListAtIndex:(NSUInteger)idx 
{ 
    if ([NSThread isMainThread]) 
    { 
     NSLog(@"insert main thread"); 
    } 
    else 
    { 
     NSLog(@"insert not main thread"); 
    } 
    [_marr insertObject:anObject atIndex:idx]; 
} 


- (void)removeObjectFromListAtIndex:(NSUInteger)idx 
{ 
    [_marr removeObjectAtIndex:idx]; 
} 
- (void)replaceObjectInListAtIndex:(NSUInteger)idx withObject:(id)anObject 
{ 
    [_marr replaceObjectAtIndex:idx withObject:anObject]; 
} 
- (void)observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context 
{ 
    NSIndexSet *indices = [change objectForKey:NSKeyValueChangeIndexesKey]; 
    if (indices == nil) 
     return; // Nothing to do 

    // Build index paths from index sets 
    NSUInteger indexCount = [indices count]; 
    NSUInteger buffer[indexCount]; 
    [indices getIndexes:buffer maxCount:indexCount inIndexRange:nil]; 

    NSMutableArray *indexPathArray = [NSMutableArray array]; 
    for (int i = 0; i

Trả lời

7

Tôi chạy vào chính xác cùng một vấn đề ngày hôm nay. Tóm lại, lý do là bạn không thể thực hiện các nhiệm vụ liên quan đến UIKit, như cập nhật một bảng, hoặc trong trường hợp của tôi là một Textview, từ hàng đợi công văn nền. Kiểm tra liên kết bên dưới để biết thêm chi tiết.

comparison GCD vs. performSelectorInBackground: dispatch_async not in background

Một giải pháp có thể được như sau: thay vì gán dữ liệu mới của bạn trong khối cập nhật của bạn trực tiếp vào biến KVO mà nguyên nhân của vụ tai nạn, bạn cử một khối mà thực hiện điều này với hàng đợi chính, từ bên trong khối cập nhật của bạn. Nếu bạn sử dụng hàm dispatch_async_f để làm điều này, bạn có thể chuyển một con trỏ tới dữ liệu của bạn dưới dạng ngữ cảnh.

Như thế này:

dispatch_async(yourQueue, ^() { 
    NSArray *data; 
    // do stuff to alloc and fill the array 
    // ... 
    dispatch_async(dispatch_get_main_queue(), ^() { 
    myObj.data = data; // the assignment, which triggers the KVO. 
    }); 
}); 

Đối với tôi này hoạt động mà không giữ lại và phát hành dữ liệu. Không chắc chắn, nếu điều này đúng.

+0

cảm ơn, tôi sẽ xem xét. – scorpiozj

+0

Sản phẩm có hoạt động không? Sau đó, bạn có thể đánh dấu câu hỏi là trả lời – tomk

+0

nó có thể không quan trọng với chủ đề chính/nền như tôi đã làm trong các ứng dụng khác với cùng một cách và nó hoạt động tốt. SO Tôi vẫn không biết vấn đề là gì. – scorpiozj