uitableview禁用重用是怎样实现cell的重用的

& & UITableView通过重用单元格来达到节省内存的目的:通过为每个单元格指定一个重用标识符(reuseIdentifier),即指定了单元格的种类,以及当单元格滚出屏幕时,允许恢复单元格以便重用.对于不同种类的单元格使用不同的ID,对于简单的表格,一个标识符就够了.& & 假如一个TableView中有10个单元格,但是屏幕上最多能显示4个,那么实际上iPhone只是为其分配了4个单元格的内存,没有分配10个,当滚动单元格时,屏幕内显示的单元格重复使用这4个内存。实际上分配的Cell个数为屏幕最大显示数, 当有新的Cell进入屏幕时,会随机调用已经滚出屏幕的Cell所占的内存,这就是Cell的重用。& & 对于多变的自定义cell,这种重用机制会导致内容出错。为了解决这种出错的,经过反复的google,终于找到一个适合的方法。就是把原来的& & UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:defineString];修改为:& & UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];& & 这样就能解决掉cell重用机制导致的问题了。
声明:该文章系网友上传分享,此内容仅代表网友个人经验或观点,不代表本网站立场和观点;若未进行原创声明,则表明该文章系转载自互联网;若该文章内容涉嫌侵权,请及时向
上一篇:下一篇:
相关经验教程
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益今天看啥 热点:
UITableView的优化技巧,uitableview技巧
在IOS开发中, UITableView是最常用到的复杂控件. 使用不难, 但想用好却不容易. 需要考虑到后台数据的设计, tableViewCell的设计和优化, 以及tableView的效率等问题.
本文主要介绍一下UITableView的常见优化技巧, 主要参考博客:
VVeboTableViewDemo.
tableView的优化主要思路是:
1. 异步渲染内容到图片。
2. 按照滑动速度按需加载内容。
3. 重写处理网络图片加载。
4. 缓存一切可缓存的, 用空间换时间.
UITableViewCell的重用机制是最常见也是最有效的优化方式之一.
使用dequeueReusableCellWithIdentifier来实现布局相同的cell的重用, 也可以通过cellForRowAtIndexPath 直接复用某个cell. 如
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
WeiboTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (cell == nil) {
cell = [[WeiboTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
[self drawCell:cell withIndexPath:indexPath];
因为cellForRowAtIndexPath方法调用非常频繁,初始化,上下滚动,刷新都要调用. 所以cell的标示声明为静态变量更好。
static NSString *cellIdentifier = @“Tracks”;
避免cell的重新布局
cell的布局填充等操作比较耗时, 一般可在创建时就布局好. 如可将cell单独放到一个class中WeiboTableViewCell, 重写其initWithStyle方法, 在其中将cell的布局设置完成.
创建cell完成之后, 调用drawCell往其中填充内容即可, 即将cell的布局及填充分开执行, 且尽量将要填充的data提前准备好.
- (void)drawCell:(WeiboTableViewCell *)cell withIndexPath:(NSIndexPath *)indexPath {
NSDictionary *data = [datas objectAtIndex:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleN
[cell clear];
cell.data =
if (needLoadArr.count&0 && [needLoadArr indexOfObject:indexPath]==NSNotFound) {
[cell clear];
if (scrollToToping) {
[cell draw];
提前计算并缓存cell的属性及内容
因UITableView继承自UIScrollView, 因此其布局主要表现为Plain和Grouped两种风格. 需先确定其contentSize及每个cell的位置, 才会将其放进去. 如:
要显示100个cell,而当前屏幕只能显示5个. 则reload的时候,会先调用100次heightForRowAtIndexPath方法, 然后调用5次cellForRowAtIndexPath方法; 滚动屏幕时, 每当cell进入屏幕, 都会调用一次heightForRowAtIndexPath和cellForRowAtIndexPath方法.
subView的绘制
如果有多个不同风格的cell, 可以给每种cell指定不同的重用标识符. 然后使用dequeue每次将其出列使用即可. 如:
NSString *cellId = [NSString stringWithFormat:@“Cell%d%d”, indexPath.section, indexPath.row];
UITableView的局部更新
我们常用[self.tableView reloadData]来进行tableView中的数据更新. 如果只是更新某个section的话, 可以使用reloadSections等进行局部的更新
self.tableView reloadRowsAtIndexPaths:&#(NSArray *)#& withRowAnimation:&#(UITableViewRowAnimation)#&
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
tableView的异步绘制
对于复杂的tableView界面, 可考虑异步绘制. 使用dispatch_async和dispatch_sync配合, 将业务逻辑与UI绘制分开. 如:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CGRect rect = [_data[@"frame"] CGRectValue];
UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor colorWithRed:250/255.0 green:250/255.0 blue:250/255.0 alpha:1] set];
CGContextFillRect(context, rect);
if ([_data valueForKey:@"subData"]) {
[[UIColor colorWithRed:243/255.0 green:243/255.0 blue:243/255.0 alpha:1] set];
CGRect subFrame = [_data[@"subData"][@"frame"] CGRectValue];
CGContextFillRect(context, subFrame);
[[UIColor colorWithRed:200/255.0 green:200/255.0 blue:200/255.0 alpha:1] set];
CGContextFillRect(context, CGRectMake(0, subFrame.origin.y, rect.size.width, .5));
float leftX = SIZE_GAP_LEFT+SIZE_AVATAR+SIZE_GAP_BIG;
float x = leftX;
float y = (SIZE_AVATAR-(SIZE_FONT_NAME+SIZE_FONT_SUBTITLE+6))/2-2+SIZE_GAP_TOP+SIZE_GAP_SMALL-5;
[_data[@"name"] drawInContext:context withPosition:CGPointMake(x, y) andFont:FontWithSize(SIZE_FONT_NAME)
andTextColor:[UIColor colorWithRed:106/255.0 green:140/255.0 blue:181/255.0 alpha:1]
andHeight:rect.size.height];
y += SIZE_FONT_NAME+5;
float fromX = leftX;
float size = [UIScreen screenWidth]-leftX;
NSString *from = [NSString stringWithFormat:@"%@
%@", _data[@"time"], _data[@"from"]];
[from drawInContext:context withPosition:CGPointMake(fromX, y) andFont:FontWithSize(SIZE_FONT_SUBTITLE)
andTextColor:[UIColor colorWithRed:178/255.0 green:178/255.0 blue:178/255.0 alpha:1]
andHeight:rect.size.height andWidth:size];
UIImage *temp = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
dispatch_async(dispatch_get_main_queue(), ^{
if (flag==drawColorFlag) {
postBGView.frame =
postBGView.image = nil;
postBGView.image =
[self drawText];
NSTimer在UITableViewCell的重用中会失效, 所以不要将timer添加到cell中. 因在滑动tableView时, timer不会触发时间函数. 因它们使用共同的runloop, 而tableView的滑动阻止了timer的时间函数.
1. 对于显示在cell中的text或其他对象上使用timer.
2. 并行实现, 主要是设置mode参数:
NSTimer* timer = [NSTimer timerWithTimeInterval:0.005 target:self selector:@selector(timerFireMethod:) userInfo:@"finishAnimation" repeats:YES];
NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
[currentRunLoop addTimer:timer forMode:NSRunLoopCommonModes];
timer = [NSTimer timerWithTimeInterval:5.0 target:self selector:@selector(SendHeartBeat) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:heartTimer forMode:NSDefaultRunLoopMode];
优化touch事件传递
把不需要接受touch的view的userInteractionEnabled设为0.
自定义cell的绘制
添加大量控件会导致资源开销很大, 可以考虑直接绘制drawRect.
这一条暂时还不清楚如何实现, 因此不够详细, 有待进一步补充.
cell的按需加载
从UIScrollView的角度出发, 对cell进行按需加载, 即滚动很快时候, 只加载目标范围内的cell.
if (needLoadArr.count&0 && [needLoadArr indexOfObject:indexPath]==NSNotFound) {
[cell clear]; return;
例如: 如果目标行与当前行相差超过指定行数,只在目标滚动范围的前后指定3行加载。
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
NSIndexPath *ip = [self indexPathForRowAtPoint:CGPointMake(0, targetContentOffset-&y)];
NSIndexPath *cip = [[self indexPathsForVisibleRows] firstObject];
NSInteger skipCount = 8;
if (labs(cip.row-ip.row)&skipCount) {
NSArray *temp = [self indexPathsForRowsInRect:CGRectMake(0, targetContentOffset-&y, self.width, self.height)];
NSMutableArray *arr = [NSMutableArray arrayWithArray:temp];
if (velocity.y&0) {
NSIndexPath *indexPath = [temp lastObject];
if (indexPath.row+33) {
[arr addObject:[NSIndexPath indexPathForRow:indexPath.row-3 inSection:0]];
[arr addObject:[NSIndexPath indexPathForRow:indexPath.row-2 inSection:0]];
[arr addObject:[NSIndexPath indexPathForRow:indexPath.row-1 inSection:0]];
[needLoadArr addObjectsFromArray:arr];
不要实现无用的delegate方法
使用tableView要遵循两个协议, 而我们只需实现必需要的代理方法即可.
UITableViewDelegate
主要提供cell的展示及样式控制, cell的选择, 指定section的头尾显示, 协助完成cell的排序和删除等功能.
//_______________________________________________________________________________________________________________
// this represents the display and behaviour of the cells.
@protocol UITableViewDelegate&NSObject, UIScrollViewDelegate&
// Display customization
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexP
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
// Variable height support
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexP
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)
// Use the estimatedHeight methods to quickly calcuate guessed values which will allow for fast load times of the table.
// If these methods are implemented, the above -tableView:heightForXXX calls will be deferred until views are ready to be displayed, so more expensive logic can be placed there.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(7_0);
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section NS_AVAILABLE_IOS(7_0);
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForFooterInSection:(NSInteger)section NS_AVAILABLE_IOS(7_0);
// Section header & footer information. Views are preferred over title should you decide to provide both
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)
// custom view for header. will be adjusted to default or specified header height
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)
// custom view for footer. will be adjusted to default or specified footer height
// Accessories (disclosures).
- (UITableViewCellAccessoryType)tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath NS_DEPRECATED_IOS(2_0, 3_0);
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexP
// Selection
// -tableView:shouldHighlightRowAtIndexPath: is called when a touch comes down on a row.
// Returning NO to that message halts the selection process and does not cause the currently selected row to lose its selected look while the touch is down.
- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
// Called before the user changes the selection. Return a new indexPath, or nil, to change the proposed selection.
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexP
- (NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0);
// Called after the user changes the selection.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexP
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0);
// Editing
// Allows customization of the editingStyle for a particular cell located at 'indexPath'. If not implemented, all editable cells will have UITableViewCellEditingStyleDelete set for them when the table has editing property set to YES.
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexP
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0);
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0); // supercedes -tableView:titleForDeleteConfirmationButtonForRowAtIndexPath: if return value is non-nil
// Controls whether the background is indented while editing.
If not implemented, the default is YES.
This is unrelated to the indentation level below.
This method only applies to grouped style table views.
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexP
// The willBegin/didEnd methods are called whenever the 'editing' property is automatically changed by the table (allowing insert/delete/move). This is done by a swipe activating a single row
- (void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexP
- (void)tableView:(UITableView*)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexP
// Moving/reordering
// Allows customization of the target row for a particular row as it is being moved/reordered
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexP
// Indentation
- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexP // return 'depth' of row for hierarchies
// Copy/Paste.
All three methods must be implemented by the delegate.
- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(5_0);
- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender NS_AVAILABLE_IOS(5_0);
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender NS_AVAILABLE_IOS(5_0);
以上有非常多的方法, 用于cell属性的控制, 显示风格等.
除了必要的几个, heightForRowAtIndexPath, viewForHeaderInSection, didSelectRowAtIndexPath之外, 如无特殊要求, 可尽量避免实现, 以免耗时.
UITableViewDataSource
为UITableView提供显示用的数据, 指定cell的操作类型, 并根据操作及进行相应的数据更新操作. 如数据异常, 则可能导致crash.
@protocol UITableViewDataSource&NSObject&
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexP
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableV
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexP
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexP
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableV
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexP
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexP
常见的方法:
numberOfRowsInSection, cellForRowAtIndexPath, commitEditingStyle等.
版权声明:本文为博主原创文章,未经博主允许不得转载。
相关搜索:
相关阅读:
相关频道:
Android教程最近更新二次元同好交流新大陆
扫码下载App
汇聚2000万达人的兴趣社区下载即送20张免费照片冲印
扫码下载App
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
悠悠电台,NJ的乐园
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
阅读(5746)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
在LOFTER的更多文章
loftPermalink:'',
id:'fks_',
blogTitle:'iOS之美:如何优化UITableView的性能',
blogAbstract:'在iOS App中,UITableView应该是使用率最高的,同时也是最为复杂的视图。 几乎所有自带的应用中都能看到它的身影,可见它的重要性。\n在使用UITableView时,会经常遇到性能上的问题,普遍表现在滚动时比较卡,特别是table cell中包含图片的情况时。实际上只要针对性地优化一下,这种问题就不会有了。有兴趣的可以看看'
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}

我要回帖

更多关于 uitableview 重用问题 的文章

 

随机推荐