iOS 面试题汇总(二)

1.什么情况使用 weak 关键字,相比 assign 有什么不同?


A:什么情况使用 weak 关键字?

  • 强引用关系的对象会发生循环引用时用weak关键字;
  • 已经被强引用的对象,如Interface Builder创建的视图被声明为weak。

weak 相比 assign 有什么不同?

  • weak 必须修饰对象,assign还可以修饰非对象;
  • weak 修饰的属性所指向的对象销毁后,该属性会被置为nil,而assign修改的属性所指向的对象销毁后,属性仍然指向对象分配的内存地址成为野指针。

2.怎么用 copy 关键字?(我觉得题目应该改为什么情况使用 copy 关键字,怎么用 copy 关键字这个问法有点奇怪,比如怎么用手机,那问题的答案就是手机的使用说明书,按这样来回答问题,那我们就应该说,声明属性时加上 copy 关键字)


A:属性想拥有独立的赋值副本,且赋值对象的类遵守 NSCopying 协议,这时我们可以使用 copy 关键字。

3.这个写法会出什么问题: @property (copy) NSMutableArray *array;


A:

  • 问题一:由于属性声明为 copy, 所以它最终指向的是一个 NSArray,对它调用 NSMutableArray 中定义的方法会导致应用奔溃;
  • 问题二:如果是开发 iOS 程序,这会影响性能。

扩展:

Apple 在 The Objective-C Programming Language 中介绍 atomic 时说:

Properties are atomic by default so that synthesized accessors provide robust access to properties in a multithreaded environment—that is, the value returned from the getter or set via the setter is always fully retrieved or set regardless of what other threads are executing concurrently. If you specify strong, copy, or retain and do not specify nonatomic, then in a reference-counted environment, a synthesized get accessor for an object property uses a lock and retains and autoreleases the returned value—the implementation will be similar to the following:

1
2
3
4
5
6
7
[_internal lock]; // lock using an object-level lock

id result = [[value retain] autorelease];

[_internal unlock];

return result;

从文档的修改记录来看,最后一次修改时间是2011-10-12,维基上查了下 Mid 2011(July) 的 MacBook Air 的低配处理器参数为: 1.6 GHz (i5-2467M) dual-core Intel Core i5 with 3 MB shared L3 cacheOptional 1.8 GHz (i7-2677M) dual-core Intel Core i7 with 4 MB shared L3 cache, 内存为:2 GB (11" base model; Optional 4 GB) or 4 GB of 1333 MHz DDR3 SDRAM (all other models),目前 Apple 还支持 iPhone 5S,它的处理器:64-bit 1.3 GHz dual-core Apple Cyclone,内存:1 GB LPDDR3 RAM,很遗憾数据好像没有全面超越,不过也比较接近了,当设备淘汰到 iPhone 6S 时,我们有理由在 iOS 开发中直接使用 atomic 关键字了。

继续阅读

iOS Unit Testing With OCMock

单元测试是我们保障代码质量的重要手段, Apple 对此也十分重视,这点可以从 Xcode 新建工程时会自动创建单元测试的 Target 看出来。单元测试牵涉的内容很多,这篇文章是目前我对单元测试的理解。

既然是单元测试,那么什么是单元呢?我没有去考证,但我是这么理解的:面向对象编程范式里一切皆对象,而对象是由实例变量和方法组成,对象之间通过方法互相作用,我们的应用可以看作是一个对象图,对象图上的对象相互作用来实现我们的需求。这么看来我们的单元应该是对象的方法。

对象的方法在工作的时候可能要依赖其他对象,为了去除依赖对象对测试的影响,我们引入 Mock.

Mocks are ‘fake’ objects with pre-defined behavior to stand-in for concrete objects during testing. – HackaZach

引用 Mock 之后,我们在单元测试中如何使用它呢?

The general recipe for using mocks in unit-tests is:

  1. Create the mock object
  2. Specify the expected invocations and return values
  3. Associate the mock object with the code under test
  4. Execute the code under test
  5. Validate that your assertions are correct
继续阅读

iOS App 开发问题汇总(五)

1.On iOS 7 and later, how do I take a snapshot of my view and save the result in a UIImage?

Solution:

1
2
3
4
5
6
7
8
9
- (UIImage *)snapshot:(UIView *)view
{
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES, 0);
    [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return image;
}

Reference:View Snapshots on iOS 7

2.How to present a view controller on iOS7 without the status bar overlapping?

Solution:The easiest workaround I’ve found is to wrap the view controller you want to present inside a navigation controller, and then present that navigation controller.

1
2
3
4
MyViewController *vc = [MyViewController new];
UINavigationController *nvc = [[UINavigationController alloc] 
    initWithRootViewController:vc];
[self presentViewController:nvc animated:YES completion:nil];

3.代码创建 UITableView 时如何使用各种系统样式的 UITableViewCell?

Solution:

1
2
3
4
5
6
7
8
9
10
11
12
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *sCellID = @"CellID";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:sCellID];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:sCellID];
    }
    // Configure the cell...
    
    return cell;
}
继续阅读