我使用UITableViewController
显示来自网络服务的文章列表。检索数据后,将调用此委托方法:
-(void)itemsDownloaded:(NSArray *)items
{
// Set the items to the array
_feedItems = items;
// Reload the table view
[self.tableView reloadData];
}
我还使用自定义单元格,以便标签的高度发生变化,因此使用以下代码显示整篇文章的标题(遵循本教程Table View Cells With Varying Row Heights) :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = @"BasicCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
[self configureCell:cell forRowAtIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([cell isKindOfClass:[CustomTableViewCell class]])
{
CustomTableViewCell *textCell = (CustomTableViewCell *)cell;
Article *article_item = _feedItems[indexPath.row];
NSString *fulltitle = article_item.Title;
// fulltitle = article_item.Cat_Name; // testing category name
if (article_item.Subtitle != nil && article_item.Subtitle.length != 0) {
fulltitle = [fulltitle stringByAppendingString:@": "];
fulltitle = [fulltitle stringByAppendingString:article_item.Subtitle];
}
textCell.lineLabel.text = fulltitle;
textCell.lineLabel.numberOfLines = 0;
textCell.lineLabel.font = [UIFont fontWithName:@"Novecento wide" size:12.0f];
}
}
- (CustomTableViewCell *)prototypeCell
{
NSString *cellIdentifier = @"BasicCell";
if (!_prototypeCell)
{
_prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:cellIdentifier];
}
return _prototypeCell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
[self configureCell:self.prototypeCell forRowAtIndexPath:indexPath];
self.prototypeCell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.tableView.bounds), CGRectGetHeight(self.prototypeCell.bounds));
[self.prototypeCell layoutIfNeeded];
CGSize size = [self.prototypeCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
return size.height+1;
}
第一个问题是方法forRowAtIndexPath
被调用两次而不是一次。因此,如果_feeditems
有10个对象,则该方法被调用20次。第二次调用该方法时,我从获取释放后获得ID
对象Cat_Name
的两个属性(Article
和null
):
*** -[CFString retain]: message sent to deallocated instance 0x9c8eea0
*** -[CFNumber respondsToSelector:]: message sent to deallocated instance 0x9c8e370
尝试显示类别名称时会触发EXC_BAD_ACCESS
。
我不确定究竟是什么问题,我已经尝试删除代码以改变标签的高度,看看是否通过使用此代码导致了这个问题:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Retrieve cell
NSString *cellIdentifier = @"BasicCell";
UITableViewCell *myCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
// Get article
Article *item = _feedItems[indexPath.row];
myCell.textLabel.text = item.Title;
return myCell;
}
唯一的区别是,如果_feeditems
有10个对象,则该方法被调用一次,意味着10次。但文章的属性ID
和Cat_Name
仍然被取消分配。
在获取数据时,所有对象都是' _feeditems
中的属性完好无损,没有解除分配。我想它发生在cellForRowAtIndexPath
或forRowAtIndexPath
。
更新
正如@Ilya K所建议的那样,没有从configureCell:forRowAtIndexPath:
调用tableView:heightForRowAtIndexPath
就停止了两次调用它的问题。我还试过拥有feedItems
的财产。到目前为止,这是在@interface
(TableViewController.m)的Controller
中设置的:
@interface TableViewController () {
HomeModel *_homeModel;
NSArray *_feedItems;
Article *_selectedArticle;
}
我已将其从界面中删除,并将其添加为property
(TableViewController.h):
@interface TableViewController : UITableViewController <HomeModelProtocol>
@property (weak, nonatomic) IBOutlet UIBarButtonItem *sidebarButton;
@property (nonatomic, strong) CustomTableViewCell *prototypeCell;
@property(nonatomic) NSString *type;
@property(nonatomic) NSString *data;
@property(copy) NSArray *_feedItems;
@end
尽管如此,它仍然会发出解除分配的消息。
更新2
我已使用Instruments
Zombie
模板查看了代码(感谢此问题ViewController respondsToSelector: message sent to deallocated instance (CRASH)的答案)。这是我从Instruments
获得的错误:
Zombie Messaged
An Objective-C message was sent to a deallocated 'CFString (immutable)' object (zombie) at address: 0x10c64def0
所有Release/Retain Event Types
指向以下方法connectionDidFinishLoading
,该方法在从Web服务检索JSON数据时使用,并为检索到的每篇文章创建Article
个对象:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Create an array to store the articles
NSMutableArray *_articles = [[NSMutableArray alloc] init];
// Parse the JSON that came in
NSError *error;
// Highlighted in blue
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:_downloadedData options:kNilOptions error:&error];
NSArray *fetchedArr = [json objectForKey:@"result"];
// Loop through Json objects, create question objects and add them to our questions array
for (int i = 0; i < fetchedArr.count; i++)
{
NSDictionary *jsonElement = fetchedArr[i];
// Create a new location object and set its props to JsonElement properties
Article *newArticle = [[Article alloc] init];
newArticle.ID = jsonElement[@"ID"];
newArticle.Title = jsonElement[@"Title"];
newArticle.Subtitle = jsonElement[@"Subtitle"];
newArticle.Content = jsonElement[@"Content"];
newArticle.ImageUrl = jsonElement[@"ImageUrl"];
newArticle.Author = jsonElement[@"Author"];
newArticle.PostId = jsonElement[@"PostId"];
newArticle.ArticleOrder = jsonElement[@"ArticleOrder"];
newArticle.Cat_Id = jsonElement[@"CategoryId"];
// Highlighted in yellow
newArticle.Cat_Name = jsonElement[@"CategoryName"];
// Add this article object to the articles array
// Highlighted in yellow
[_articles addObject:newArticle];
}
// Ready to notify delegate that data is ready and pass back items
if (self.delegate)
{
[self.delegate itemsDownloaded:_articles];
}
}
我仍然无法弄清楚出了什么问题。
更新3
对connectionDidFinishLoading
进行更多测试我已删除了要释放的两个属性,并且未显示已释放的消息。我不知道导致这两个属性(ID
和Cat_Name
)被解除分配的原因,此时无法从任何地方访问这些属性。
答案 0 :(得分:1)
您不需要从tableView:heightForRowAtIndexPath调用configureCell:forRowAtIndexPath:您应该使用带有sizeWithAttributes的Article对象来确定单元格高度:
您的prototypeCell函数只是创建了类型为CustomTableViewCell的无关空单元格,并且没有必要尝试重新调整它的大小。
tableView:cellForRowAtIndexPath:每当你的tableview需要重绘时调用,例如滚动时。这意味着你的_feeditems数组应该被分配并保持一致,以便在实例生命周期的任何时候使用UITableView。
还要确保为_feeditems声明属性并使用此属性分配数据。
实施例: @property(强)NSArray * feeditems;或@property(复制)NSArray * feeditems;
in itemsDownloaded: self.feeditems = items;
答案 1 :(得分:0)
最后解决了deallocated messages
问题。将Instruments
与Zombie
模板一起使用时(使用Instruments
和Zombie
模板:ViewController respondsToSelector: message sent to deallocated instance (CRASH)),我发现这一行:
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:_downloadedData options:kNilOptions error:&error];
connectionDidFinishLoading
方法中的导致了这个问题。我搜索了NSJSONSerialization causing deallocation messages
,我从这个问题Loading properties from JSON, getting "message sent to deallocated instance"得到了答案。 Article
类的一些属性设置为assign
而不是strong
:
@interface Article : NSObject
@property (nonatomic, assign) NSNumber *ID; // changed assign to strong
@property (nonatomic, strong) NSString *Title;
@property (nonatomic, strong) NSString *Subtitle;
@property (nonatomic, strong) NSString *Content;
@property (nonatomic, strong) NSString *ImageUrl;
@property (nonatomic, assign) NSNumber *PostId; // changed assign to strong
@property (nonatomic, strong) NSString *Author;
@property (nonatomic, assign) NSNumber *ArticleOrder; // changed assign to strong
@property (nonatomic, assign) NSNumber *Cat_Id; // changed assign to strong
@property (nonatomic, assign) NSString *Cat_Name; // changed assign to strong
@end
将属性更改为strong
后,所有deallocated messages
都已停止。
我知道这个错误似乎对每个项目非常具体,其原因可能会有所不同,但如果有人有类似的东西,这就是我解决它的方法。