【主要是整理问答】
1.如何理解self = [super init]
这个问题这么分析. 我们要完成的工作是对子类对象进行初始化.
这个我们可以把这个子类对象的初始化分成两部分: 继承自父类的对象的初始化 + 子对象本身对象的初始化.
所以[super init] 其实是对父类对象进行初始化,
if( self = [super init] )
{
}
在括号里面再对子类新增对象(也可以对父类对象)的初始化操作.
self = [super init] 其实就是"subclass is a instance of the superclass"这条面向对象原则的体现.
2.viewDidLoad, viewWillDisappear, viewWillAppear等区别及各自的加载顺序
http://blog.csdn.net/silva_831/article/details/10511923
3.UITableView-右侧可以按字母检索
#pragma mark 返回每组标题索引 -(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView{ NSLog(@"生成组索引"); NSMutableArray *indexs=[[NSMutableArray alloc]init]; for(KCContactGroup *group in _contacts){ [indexs addObject:group.name]; } return indexs; }3.UITableView-数据源方法
#pragma mark 返回分组数 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
#pragma mark 返回每组行数 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
#pragma mark返回每行的单元格 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
#pragma mark 返回每组头标题名称 -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
#pragma mark 返回每组尾部说明 -(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section各方法的执行顺序:
计算分组数->计算分组行数->生成分组索引->生成单元格
*:值得指出的是生成单元格的方法并不是一次全部调用,而是只会生产当前显示在界面上的单元格,当用户滚动操作时再显示其他单元格
【其他单元格色属性,高度,高亮之类的可以在代理方法中实现】
4.UITableView 刷新数据方法
①
//刷新表格 [_tableView reloadData];
②
//刷新表格 NSArray *indexPaths=@[_selectedIndexPath];//需要局部刷新的单元格的组、行 [_tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationLeft];//后面的参数代表更新时的动画
第一种实际开发中不可取,因为是会把整个tableview的数据源方法重新执行一遍,第二个是局部刷新
5.UITableView - 性能优化 (重用CELL)
在UITableView内部有一个缓存池,初始化时使用initWithStyle:(UITableViewCellStyle) reuseIdentifier:(NSString *)方法指定一个可重用标识,就可以将这个cell放到缓存池。然后在使用时使用指定的标识去缓存池中取得对应的cell然后修改cell内容即可。
#pragma mark返回每行的单元格 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ //NSIndexPath是一个对象,记录了组和行信息 NSLog(@"生成单元格(组:%i,行%i)",indexPath.section,indexPath.row); KCContactGroup *group=_contacts[indexPath.section]; KCContact *contact=group.contacts[indexPath.row]; //由于此方法调用十分频繁,cell的标示声明成静态变量有利于性能优化 static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1"; //首先根据标识去缓存池取 UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier]; //如果缓存池没有到则重新创建并放到缓存池中 if(!cell){ cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier]; } cell.textLabel.text=[contact getName]; cell.detailTextLabel.text=contact.phoneNumber; NSLog(@"cell:%@",cell); return cell; }
- -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)方法调用很频繁,无论是初始化、上下滚动、刷新都会调用此方法,所有在这里执行的操作一定要注意性能;
- 可重用标识可以有多个,如果在UITableView中有多类结构不同的Cell,可以通过这个标识进行缓存和重新; (这个我在一次面试的时候被问到了..当时还是不太清楚,就知道缓冲池和重用,不知道重用是修改cell内容)
6.UITableViewCell的accesoryType属性
typedef NS_ENUM(NSInteger, UITableViewCellAccessoryType) { UITableViewCellAccessoryNone, // 不显示任何图标 UITableViewCellAccessoryDisclosureIndicator, // 跳转指示图标 UITableViewCellAccessoryDetailDisclosureButton, // 内容详情图标和跳转指示图标 UITableViewCellAccessoryCheckmark, // 勾选图标 UITableViewCellAccessoryDetailButton NS_ENUM_AVAILABLE_IOS(7_0) // 内容详情图标 };cell 中的开关 是 UISwitch控件
7.自定义UITableViewCell
实现自定义UITableViewCell需要分为两步:第一初始化控件;第二设置数据,重新设置控件frame。原因就是自定义Cell一般无法固定高度,很多时候高度需要随着内容改变。此外由于在单元格内部是无法控制单元格高度的,因此一般会定义一个高度属性用于在UITableView的代理事件中设置每个单元格高度。
- 对于单行文本数据的显示调用- (CGSize)sizeWithAttributes:(NSDictionary *)attrs;方法来得到文本宽度和高度。
- 对于多行文本数据的显示调用- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)context ;方法来得到文本宽度和高度;同时注意在此之前需要设置文本控件的numberOfLines属性为0。
- 通常我们会在自定义Cell中设置一个高度属性,用于外界方法调用,因为Cell内部设置Cell的高度是没有用的,UITableViewCell在初始化时会重新设置高度。
8.Objective-C中的instancetype和id关键字