我试图保存要在sqllite3
数据库中上传的资产列表,但是当我解析数据库并将资产设置为数组时,请尝试使用资产我得到一个{ {1}}错误。
SIGABRT
我将ALAsset *asset = (ALAsset *) assets[indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:@"image%d: ready to upload.",indexPath.row];
cell.detailTextLabel.text = @"1.3MB to folder <server folder>";
[[cell imageView] setImage:[UIImage imageWithCGImage:[asset thumbnail]]];// SIGABRT ERROR
作为字符串(TEXT)保存到数据库ALAsset
UTF8formatting
在上面的代码中我试过:
NSMutableArray *tmpArray = [NSMutableArray alloc]init];
///get sql
[tmpArray addObject:someStringFromSQL];
///end sql loop
assets = [tmpArray mutableCopy];
那并没有用。
这是错误:
[[cell imageView] setImage:[UIImage imageWithCGImage:[(ALAsset *) asset thumbnail]]];// SIGABRT ERROR
有什么建议吗?
另外作为一个附带问题:有谁知道如何从资产中获取文件大小(即1.3MB)?
BLOCK:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString thumbnail]: unrecognized selector sent to instance 0xc0a7800'
答案 0 :(得分:1)
您必须浏览与保存和检索功能相关的所有代码库。
但是,这里有一些很好的提示。
ALAsset
个网址,而不是将整个ALAsset
保存为字符串。ALAsset
Url并将其转换为NSUrlString。希望这会对你有所帮助。
答案 1 :(得分:1)
您的代码示例存在一些问题:
图像检索是异步发生的,因此当您尝试更新图像时,您需要确保单元格仍然可见(并且不会重复用于其他NSIndexPath
)。
在这种情况下,ALAssetsLibrary
的检索可能会非常快,以至于这并不重要,但这是一种熟悉的好模式,因为如果你曾经通过互联网检索图像,这个问题变得越来越重要。
由于单元格正在被重用,如果您没有立即找到图像并且必须异步更新它,请确保在启动异步过程之前重置UIImageView
。否则,你会看到用新的图像替换旧图像的“闪烁”。
您正在为您的手机使用UITableViewCell
。问题在于,它会根据时间cellForRowAtIndexPath
完成时图像的大小来布局单元格。
这有两个简单的解决方案。首先,您可以将单元格的imageView
初始化为正确大小的占位符图像。 (我通常有一个名为placeholder.png
的图像,它全部为白色或全部透明,我添加到我的项目中,这是我在下面使用的。)这将确保单元格正确布局,以便在异步时稍后设置图像,细胞将已经正确布局。
其次,您可以使用预先修复布局的自定义单元格,绕过标准UITableViewCell
的烦恼,其布局取决于使用的初始图像。
我建议使用NSCache
来保存缩略图图片。这样可以避免在向前和向后滚动时从ALAssetsLibrary
获取缩略图时不断重新检索缩略图。不幸的是,iOS 7打破了一些精彩的NSCache
内存压力逻辑,所以我建议一个缓存来响应内存压力,并在必要时自行清除。
无论如何,把它们放在一起,就会得到类似的东西:
@interface ViewController ()
@property (nonatomic, strong) NSMutableArray *assetGroups;
@property (nonatomic, strong) ALAssetsLibrary *library;
@property (nonatomic, strong) ThumbnailCache *imageCache;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.imageCache = [[ThumbnailCache alloc] init];
self.assetGroups = [NSMutableArray array];
self.library = [[ALAssetsLibrary alloc] init];
[self.library enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if (!group) {
[self.tableView reloadData];
return;
}
CustomAssetGroup *assetGroup = [[CustomAssetGroup alloc] init];
assetGroup.name = [group valueForProperty:ALAssetsGroupPropertyName];
assetGroup.assetURLs = [NSMutableArray array];
[group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result) {
[assetGroup.assetURLs addObject:[result valueForProperty:ALAssetPropertyAssetURL]];
}
}];
[self.assetGroups addObject:assetGroup];
} failureBlock:^(NSError *error) {
NSLog(@"%s: enumerateGroupsWithTypes error: %@", __PRETTY_FUNCTION__, error);
}];
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.assetGroups.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
CustomAssetGroup *group = self.assetGroups[section];
return [group.assetURLs count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
CustomAssetGroup *group = self.assetGroups[section];
return group.name;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
// note, these following three lines are unnecessary if you use cell prototype in Interface Builder
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
CustomAssetGroup *group = self.assetGroups[indexPath.section];
NSURL *url = group.assetURLs[indexPath.row];
NSString *key = [url absoluteString];
UIImage *image = [self.imageCache objectForKey:key];
if (image) {
cell.imageView.image = image;
} else {
UIImage *placeholderImage = [UIImage imageNamed:@"placeholder.png"];
cell.imageView.image = placeholderImage; // initialize this to a placeholder image of the right size
[self.library assetForURL:url resultBlock:^(ALAsset *asset) {
UIImage *image = [UIImage imageWithCGImage:asset.thumbnail]; // note, use thumbnail, not fullResolutionImage or anything like that
[self.imageCache setObject:image forKey:key];
// see if the cell is still visible, and if so, update it
// note, do _not_ use `cell` when updating the cell image, but rather `updateCell` as shown below
UITableViewCell *updateCell = (id)[tableView cellForRowAtIndexPath:indexPath]; // not to be confused with similarly named table view controller method ... this one checks to see if cell is still visible
if (updateCell) {
[UIView transitionWithView:updateCell.imageView duration:0.1 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
updateCell.imageView.image = image;
updateCell.textLabel.text = asset.defaultRepresentation.filename;
} completion:nil];
}
} failureBlock:^(NSError *error) {
NSLog(@"%s: assetForURL error: %@", __PRETTY_FUNCTION__, error);
}];
}
return cell;
}
@end
以上使用以下类:
/** Thumbnail cache
*
* This cache optimizes retrieval of old thumbnails. This purges itself
* upon memory pressure and sets a default countLimit.
*/
@interface ThumbnailCache : NSCache
// nothing needed here
@end
@implementation ThumbnailCache
/** Initialize cell
*
* Add observer for UIApplicationDidReceiveMemoryWarningNotification, so it purges itself under memory pressure
*/
- (instancetype)init
{
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(removeAllObjects) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
self.countLimit = 50;
};
return self;
}
/** Dealloc
*
* Remove observer before removing cache
*/
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
}
@end
和
/** Custom AssetGroup object
*
* This is my model object for keeping track of the name of the group and list of asset URLs.
*/
@interface CustomAssetGroup : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSMutableArray *assetURLs;
@end
@implementation CustomAssetGroup
// nothing needed here
@end