iOS 口试之三道题

iOS 面试之三道题

1、定义宏实现MAX或者MIN.

  • 菜鸟的答案是这样的:
#define MAX(X,Y) X>Y ? X : Y

验证:当输入MAX(1 == 3, 2)本来结果期望的是2,可实际结果却是0?

  • 高手的答案是这样的:
#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))

到这里,或许大部分人都说没有问题了,大学的时候老师都是这么教的啊?你不能再说错了吧。错不错,不能光说不练,我们举例说明吧。
验证代码段如下:

float x = 1.5f;
float y = 2.0f;
float result = MAX(++x, y);
printf("result=%f,x=%f", result, x);

最后x和result的值都是3.5,为什么呢?MAX(++x, y) 展开后是这样的((++x) > (y) ? (++x) : (y)) x自增两次,有副作用啊!

  • 大牛的答案是这样的:
#define MAX(x,y) ({ \
        typeof(x) _max1 = (x);\
        typeof(y) _max2 = (y); \
        (void) (&_max1 == &_max2); \
        _max1 > _max2 ? _max1 : _max2; })

经验证上面两种情况,没有问题了。
说明:这个宏的写法其实是Linux内核MAX的实现方式。说明几点,(1) typeof(x)的用途是得到x的类型信息,比如typeof(10)为int, typeof(1.2f)为double, (2)(void)(&_x == &_y);这一句的作用是判断_x和_y的类型是否一样,如果不一样的话,编译器会给出警告信息。

2、讲述UITableView的重用机制?

UITableView为了节约内存和高效,会为同一类的cell设置一个唯一标示符,当滑动的时候如果这个cell滑出屏幕,那么就将这个cell存起来,当有新的cell需要显示的时候先从内存中找,如果找到,就直接重用,否则重新 alloc一个。那么,接下来有2个问题:
(1)如果屏幕中间只能显示10个cell,那么滑动的时候第11个cell是否是重用的?
(2)UITableView还有其它部分需要重用吗?
然后,直接上代码吧,先是第一个问题:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    _dataSource = @[@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"11"];

    _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - 64) style:UITableViewStylePlain];
    _tableView.delegate = self;
    _tableView.dataSource = self;
    [_tableView setSeparatorColor:[UIColor redColor]];

    [self.view addSubview:_tableView];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [_dataSource count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *sCellReusableIdentify = @"sCellReusableIdentify";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:sCellReusableIdentify];
    if (!cell) {
        static NSInteger tag = 1;
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:sCellReusableIdentify];
        cell.tag = tag++;
    }

    NSLog(@"tag:%ld", cell.tag);

    return cell;
}

#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return (SCREEN_HEIGHT) / 10;
}

运行结果截图如下:
iOS 口试之三道题
我们发现,无论我们怎么滑动屏幕,cell的tag最大值也是11,那么第1个问题的答案也就浮出水面了。第11个cell一定也是新申请的。

第2个问题,section的title也需要重用的(在iOS6以后),代码如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    _dataSource = @[@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"11"];

    _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - 64) style:UITableViewStylePlain];
    _tableView.delegate = self;
    _tableView.dataSource = self;
    [_tableView setSeparatorColor:[UIColor redColor]];

    [self.view addSubview:_tableView];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [_dataSource count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *sCellReusableIdentify = @"sCellReusableIdentify";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:sCellReusableIdentify];
    if (!cell) {
        static NSInteger tag = 1;
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:sCellReusableIdentify];
        cell.tag = tag++;
    }

    NSLog(@"tag:%ld", cell.tag);

    return cell;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    const int numberOfSections = 10;
    return numberOfSections;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    static NSString *sHeaderReusableIdentify = @"sHeaderReusableIdentify";
    UITableViewHeaderFooterView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:sHeaderReusableIdentify];
    if (!view) {
        view = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:sHeaderReusableIdentify];
    }

    return view;
}

#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return (SCREEN_HEIGHT) / 10;
}

3、写一个函数或者宏实现将RGB转化为一个UIColor *值.

同样是考察c语言的基本功:

#define COLOR_WITH_RGB(rgb) [UIColor colorWithRed:((float)((rgb & 0xFF0000) >> 16)) \
    green:((float)((rgb & 0xFF00) >> 8)) \
    blue:((float)((rgb & 0xFF))) \
    alpha:1]

有问题,欢迎批评指正!