如何在 tableView:heightForRowAtIndexPath: 中初始化 NSAttributedString: 是隐式递归的?

jef*_*ong 7 uitableview nsattributedstring ios

我在计算 a 的高度时遇到了一个非常奇怪的问题UITableViewCell

似乎如果我实例化一个包含一些 HTML的NSAttributedStringwith NSData,则会在当前视图上强制执行一个布局循环,最终会tableView:heightForRowAtIndexPath:再次调用。而且,在此传递中要求所有其他行的高度。幸运的是,行高请求的内部循环中没有另一组递归调用。

这是堆栈跟踪:(注意第 0 帧和第 25 帧)

#0  0x0024422c in -[FeedVC tableView:heightForRowAtIndexPath:] at /Users/me/project/Classes/controllers/FeedVC.m:371
#1  0x024516cc in __66-[UISectionRowData refreshWithSection:tableView:tableViewRowData:]_block_invoke ()
#2  0x02450fd9 in -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] ()
#3  0x02455e2f in -[UITableViewRowData rectForFooterInSection:heightCanBeGuessed:] ()
#4  0x02455f40 in -[UITableViewRowData heightForTable] ()
#5  0x022c68c2 in -[UITableView _adjustExtraSeparators] ()
#6  0x022da6d3 in -[UITableView layoutSubviews] ()
#7  0x0225a964 in -[UIView(CALayerDelegate) layoutSublayersOfLayer:] ()
#8  0x040d582b in -[NSObject performSelector:withObject:] ()
#9  0x01f7145a in -[CALayer layoutSublayers] ()
#10 0x01f65244 in CA::Layer::layout_if_needed(CA::Transaction*) ()
#11 0x01f650b0 in CA::Layer::layout_and_display_if_needed(CA::Transaction*) ()
#12 0x01ecb7fa in CA::Context::commit_transaction(CA::Transaction*) ()
#13 0x01eccb85 in CA::Transaction::commit() ()
#14 0x01ecd258 in CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) ()
#15 0x03b7836e in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#16 0x03b782bf in __CFRunLoopDoObservers ()
#17 0x03b56254 in __CFRunLoopRun ()
#18 0x03b559d3 in CFRunLoopRunSpecific ()
#19 0x03b557eb in CFRunLoopRunInMode ()
#20 0x0a2518ce in -[NSHTMLReader _loadUsingWebKit] ()
#21 0x0a25423e in -[NSHTMLReader _load] ()
#22 0x0a254ef7 in -[NSHTMLReader attributedString] ()
#23 0x0a1e7b42 in _NSReadAttributedStringFromURLOrData ()
#24 0x0a1e6577 in -[NSAttributedString(NSAttributedStringKitAdditions) initWithData:options:documentAttributes:error:] ()
#25 0x0024434a in -[FeedVC tableView:heightForRowAtIndexPath:] at /Users/me/project/Classes/controllers/FeedVC.m:374
#26 0x024516cc in __66-[UISectionRowData refreshWithSection:tableView:tableViewRowData:]_block_invoke ()
#27 0x02450fd9 in -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] ()
#28 0x0245423d in -[UITableViewRowData numberOfRows] ()
#29 0x022d1df2 in -[UITableView noteNumberOfRowsChanged] ()
#30 0x022d17a5 in -[UITableView reloadData] ()
#31 0x1281be61 in -[UITableViewAccessibility(Accessibility) reloadData] ()
#32 0x0024236b in -[FeedVC addFeedItemsWhenFinishedLoading:] at /Users/me/project/Classes/controllers/FeedVC.m:168
#33 0x00242cba in __21-[FeedVC execRequest]_block_invoke99 at /Users/me/project/Classes/controllers/FeedVC.m:210
#34 0x0011b144 in -[GRApiUpdatesFriends didParseXMLObtainingResource:error:] at /Users/me/project/Classes/api/GRApiUpdatesFriends.m:46
#35 0x002113c1 in -[GRApiRequest didReceiveResponse:HTTPStatusCode:] at /Users/me/project/Classes/GRApiRequest.m:242
#36 0x0018b96f in __40-[GRApiFetcherAF exec:withMethod:retry:]_block_invoke at /Users/me/project/Classes/GRApiFetcherAF.m:138
#37 0x0057915b in __64-[AFHTTPRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke46 at /Users/me/project/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m:137
#38 0x0436c7b8 in _dispatch_call_block_and_release ()
#39 0x043814d0 in _dispatch_client_callout ()
#40 0x0436f726 in _dispatch_main_queue_callback_4CF ()
#41 0x03c1543e in __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ ()
#42 0x03b565cb in __CFRunLoopRun ()
#43 0x03b559d3 in CFRunLoopRunSpecific ()
#44 0x03b557eb in CFRunLoopRunInMode ()
#45 0x053fe5ee in GSEventRunModal ()
#46 0x053fe42b in GSEventRun ()
#47 0x021ebf9b in UIApplicationMain ()
#48 0x0000eec6 in main at /Users/me/project/OtherSources/main.m:12
Run Code Online (Sandbox Code Playgroud)

我正在创建属性字符串,如下所示:

- (CGFloat)tableView:(UITableView*)tv heightForRowAtIndexPath:(NSIndexPath *)ip {
    NSLog(@"requested height row for index path: %d", ip.row);
    NSData *html_data = [@" " dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *out_dict, *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
    NSError *err;
    NSAttributedString *attr_str = [[NSAttributedString alloc] initWithData:html_data options:options documentAttributes:&out_dict error:&err];
}
Run Code Online (Sandbox Code Playgroud)

递归发生在 initWithData:

空白字符串只是一个示例。在我们的应用程序中,有一个实际的 HTML 字符串。

任何人都知道为什么会发生这种情况?

我无法创建一个示例项目来说明这一点,因为我似乎无法在一个简单的UITableViewController项目中重现这一点。

use*_*109 5

很难说,但我猜问题是#20。这似乎会导致代码重新输入,然后触发排队的表事件,这些事件在完成CFRunLoopRun后才应该运行。reloadData

建议的解决方法:在初始化期间创建字符串并将它们存储在 中,NSArray以便heightForRowAtIndexPath.