iOS面试题(1-5)

0D6829F1A95EA9C1B42E3FD9413D5230.jpg

1.请描述你所了解的设计模式.举例并描述其使用场景

单例模式

iOS生命周期中,有时我们只需要某个类的一个实例.

应用案例

UIApplication,UIAccelerometer,NSUserDefaults,NSNotificationCenter,NSFileManager,NSBundle,NSWorkspace,NSApplication

实现代码

//
// Singleton.h
//
@interface Singleton : NSObject
(Singleton *)sharedManager;
@property (nonatomic, strong) NSString *singletonData;
@end
//
// Singleton.m
//
#import “Singleton.h”
@implementation Singleton
static Singleton *sharedManager = nil;
+ (Singleton *)sharedManager {
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        sharedManager = [[self alloc] init];
    });
    return sharedManager;
}

委托模式

委托是为了降低一个对象的复杂度和耦合度,使其能够更具通用性而将其中一些处理置于委托对象的编码方式.通用类因为通用性(与具体应用的无关性)而变为框架类,框架类保存委托对象的指针,并在特定时刻向委托对象发送消息.

应用案例

UITextFieldDelegate
textFieldShouldBeginEditing:
textFieldDidBeginEditing:
textFieldShouldEndEditing:
textFieldDidEndEditing:
委托消息的命名有一定的定性:使用Should时,应该返回一个布尔值;使用Will时,没有返回值,表示改变之前要做的事情;使用Did时,没有返回值,表示改变之后要做的事情.
UITableView:委托对象主要对控件对象的事件和状态变化做出响应,而数据源对象是为控件对象提供数据.委托中的方法在实现时是可选的,而数据源中的方法一般必须实现

观察者模式

一个对象状态改变也会连带影响其他很多对象的状态发生改变.观察者模式复用性强且对象之间匿名通信.

应用案例

通知机制和KVO机制

通知机制

通知机制与委托机制不同的是,前者是”一对多”的对象之间的通信,后者是”一对一”的对象之间的通信
使用Utility Application工程模板,这个模板有主界面控制器(MainViewController)和翻转界面控制器(FlipsideViewController),还有应用程序委托对象AppDelegate


屏幕快照 2016-07-16 下午2.05.45.png

在MainViewController和FlipsideViewController这两个视图控制器中,注册通知者

- (void)viewDidLoad {
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleTerminate:)
                                                 name:@“AppWillTerminateNotification”
                                               object:nil];
}

解除通知

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserve:self];
}

MainViewConrtroler和FilpsideViewController的处理通知方法

- (void)handleTerminate:(NSNotification *)notification {
    NSDictionary *theData = [notification userInfo];
    if (theData != nil) {
        NSDate *date = [theData objectForKey:@"TerminateDate"];
        NSLog(@"FlipsideViewController App Terminate Date: %@", date);
  }
}

如果我们想在应用终止时投送通知,需要重写AppDelegate中的方法

- (void)applicationWillTerminate:(UIApplication *)application {
    NSDate *date = [NSDate date];
    NSDictionary *dataDict = [NSDictionary dictionaryWithObject:date forKey:@"TermineDate"];
    [[NSNotificationCenter default] postNotificationName:@"AppWillTerminateNotification" object:self userInfo:DateDict];

// 除了上面代码中所示之外,还有另外一个重载方法:
    [[NSNotificationCenter defaultCenter] postNotificationName:@"AppWillTerminateNotification" object:self];
}

// 事实上,Cocoa Touch框架该通知,当应用事件发生时,由iOS系统自动投送
// so, 删除上面的代码并修改MainViewController和FlipsideViewController中注册接收通知者的代码
- (void)viewDidLoad {
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserve:self
                                            selector:@selector(handleTerminate:)
                                                name:UIApplicationWillTerminateNotification
                                              object:nil];
}

除了应用生命周期的不同阶段有不同的通知外,很多控件也会在某些事件发生时投送通知,例如UITextField控件.在编辑过程的不同阶段会分别发出如下通知:UITextFieldTextDidBeginEditingNotification, UITextFieldTextDidChangeNotification, UITextFieldTextDidEndEditingNotification

KVO机制

KVO不像通知机制那样通过一个通知中心通知所有观察者对象,而是在对象属性变化时通知会被直接发送给观察者对象


屏幕快照 2016-07-16 下午3.43.19.png

应用程序委托对象的AppDelegate.h

@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) NSString *appStatus;  // 记录应用程序状态的变化
@property (strong, nonatomic) AppStatusWatcher *watcher;  // 定义ppStatusWatcher类型的观察者对象属性

AppDelegate.m

@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.watcher = [AppStatusWatcher new];
    
    // addObserver是要要被关注的对象
    // forKeyPath是要被关注对象的属性
    // options是为属性变化设置的选项,NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld意味着把新旧两个值都传递给观察者
    // context上下文内容,类型为(void*),如果传递"空",应是"NULL",而非"nil"
    [self addObserver:self.watcher forKeyPath:@"appStatus" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"Pass Context"];
    self.appStatus = @"launch";
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
    self.appStatus = @"inactive";
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    self.appStatus = @"background";
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    self.appStatus = @"inactive";
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    self.appStatus = @"active";
}

- (void)applicationWillTerminate:(UIApplication *)application {
    self.appStatus = @"terminate";
}

观察者AppStatusWatcher的代码

@interface AppStatusWatcher : NSObject
@end

@implementation AppStatusWatcher

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    NSLog(@"Property '%@' of object '%@' changed: %@ context: %@", keyPath, object, change, context);
}
@end

因为NSbject类实现了NSKeyValueObserving协议,所以只需声明AppStatusWatcher继承NSObject类,无需实现NSKeyValueObserving协议.
observeValueForKeyPath:ofObject:change:context:方法中的
observeValueForKeyPath参数是被关注的属性
ofObject是被关注的对象
change是字典类型,包含了属性变化的内容,这些内容与注册时属性设置的选项(options参数)有关
context是注册时传递的上下文

屏幕快照 2016-07-16 下午4.08.19.png

MVC模式

Model-ViewController,模型-视图-控制器 模式

屏幕快照 2016-07-16 下午4.10.29.png

模型:保存应用数据的状态,回应视图对状态的查询,处理应用业务逻辑,完成应用的功能,将状态的变化通知视图.
视图:为用户展示信息并提供接口,用户通过视图想控制器发出动作请求,然后再向模型发出查询状态的申请,而模型状态的变化会通知给视图
控制器:接收用户请求,根据请求更新模型.另外,控制器还会更新所选择的视图作为对用户请求的回应.控制器是视图和模型的媒介,可以降低视图和模型的耦合度,是视图和模型的权责更加清晰,从而提高开发效率.

2.不手动指定autoreleasepool的前提下,一个autorelease对象在什么时刻释放?

在MRR(Manual Retain Release, 手动保持释放), 也称为MRC(Manual Reference Counting, 手动引用计数)中,释放对象通过release或autorelease消息实现,其中release消息会立刻使引用计数减1,autorelease消息会使对象放入内存释放池中延迟释放,对象的引用计数并不变化,而是向内存释放池中添加一条记录,直到池被销毁前通知池中的所有对象全部发送release消息才真正将引用计数减少.
在iOS程序中,默认内存释放池的释放在程序结束

注意

int main(int argh, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argh, argue, nil, NSStringFromClass([AppDelegate class]));
    }
}

代码被包裹在@autoreleasepool{...}之间,这是池的作用范围,默认是整个应用.如果产生大量对象,采用autorelease释放也会导致内存泄漏.

什么时候必须使用autorelease?

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"CellIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }

    NSUInteger row = [indexPath row];
    NSDictionary *rowDic = [self.listTeams objectAtIndex:row];
    cell.textLabel.text = [rowDict objectForKey:@"name"];

    NSString *imagePath = [rowDict objectForKey:@"image"];
    imagePath = [imagePath stringByAppendingString:@".png"];
    cell.imageView.image = [UIImage imageNamed:imagePath];

    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

    return cell;
}

1> 上述代码中,cell对象不能马上释放,我们需要使用它设置表视图界面.autorelease一般用在为其他调用者提供对象的方法中,对象在该方法不能马上释放,而需要延迟释放.
2> 此外,还有一种情况需要使用autorelease,即"类级构造方法":

NSString *message = [NSString stringWithFormat:@"您选择了%@队", rowValue];

该对象的所有权虽然不是当前调用者,但它是由iOS系统通过发送autorelease消息放入到池中的.当然,这一切对于开发者都是不可见的,我们也要注意减少使用这样的语句

3.分别描述Swift和OC中的访问限制有哪些?

Swift

OC

屏幕快照 2016-07-16 下午5.14.56.png

4.简述KVC和KVO

KVC(Key Value Coding)

键值编码是Cocoa的标准组件,允许开发者通过名字(键)访问属性,而无需调用显式的存取方法.由此,系统的某些部分就可以动态访问属性,即使在编译的时候不知道属性的键是什么.这种动态访问对于nib文件的加载和Core Data尤其重要.在Mac系统上,KVC是AppleScript接口的基础部分.
valueForKeyPath:会自动把数字类型(int,float等)转换成NSNumber对象,而其他的非对象类型(结构体,指针)会转换成NSValue对象.
KVC方法有key和keyPath两个版本.键和键路径的区别在于,后者可以包含嵌套关系,用句点分开.��

用KVC实现高阶消息传递

valueForKey:有很对有用的特例,比如说NSArray和NSSet这样的容器类都覆盖了这个方法.valueForKey:被传递给容器中的每个对象,而不是对容器本身进行操作.结果会被添加进返回的容器中.这样可以很方便的用一个容器对象创建另一个容器对象.

NSArray *array = @[@"foo", @"bar", @"baz"];
NSArray *capitals = [array valueForKey:@"capitalizedString"];

方法capitalizedString被传递给NSArray中的每一项,并返回一个包含结果的新NSArray,把消息(capitalizedString)作为参数传递称为高阶消息传递(Higher Order Messaging).多个消息可以用键路径传递:

NSArray *array = @[@"foo", @"bar", @"baz"];
NSArray *capitalLengths = [array valueForKey:@"capitalizedString.length"];

以上代码对array的每一个元素调用capitalizedString,然后调用length,再把返回值封装进NSNumber对象.结果被收集进名为capitalLengths的新数组

KVO(Key Value Observing)键值观察

键值观察是就对象对象属性变化透明地通知观察者的一种机制.
实现功能:无论对象什么时候发生变化,都可以让表格单元自动更新.
KVO用addObserver:forKeyPath:options:context:开始观察,用removeObserver:forKeyPath:context:停止观察.回调总是observeValueForKeyPath:ofObject:change:context:

// KVCTableViewCell.m

- (void)removeObservation {
  if (self.isReady) {
    [self.object removeObserver:self forKeyPath:self.property];
  }
}

- (void)addObservation {
  if (self.isReady) {
    [self.object addObserver:self forKeyPath:self.property options:0 context:(void *)self];
  }
}

- (void)observeValueForKeyPat:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change {
  if ((__bridge id)context == self) {
    [self update];
  }
  else {
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
  }
}

- (void)dealloc {
  if (__object && [_property length] > 0) {
    [_object removeObserver:self forKeyPath:_property context:(void *)self];
  }
}

- (void)setObject:(id)anObject {
  [self removeObservation];
  _object = anObject;
  [self addObservation];
  [self update];
}

- (void)setProperty:(NSString *)aProperty {
  [self removeObservation];
  _property = aProperty;
  [self addObservation];
  [self update];
}
// KVCTableViewController.m

#import "RNTimer.h"
@interface KVCTableViewController ()
@property (readwrite, retain) RNTimer *timer;
@property (readwrite, retain) NSDate *now;
@end

@implementation KVCTableViewController

- (void)updateNow {
  self.now = [NSDate date];
}

- (void)viewDidLoad {
  [self updateNow];

  __weak id weakSelf = self;
  self.timer = [RNTimer repeatingTimerWithInterval:1 block:^{
    [weakSelf updateNow];
  }];
}

- (void)viewDidUnload {
  self.timer = nil;
  self.now = nil;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  static NSString *CellIdentifier = @"KVCTableViewCell";

  id cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
  if (cell == nil) {
    cell = [[[KVCTableView alloc] initWithReusableIdentifier:CellIdentifier] autorelease];
  [cell setProperty:@"now"];
  [cell setObject:self];
  }
  return cell;
}
@end

5.简述视图控制器的生命周期

20140929170950334.jpeg

loadView中的三个方法

createFields 接受参数,初始化变量
createViews 创建视图
createEvents 绑定事件.如按钮的点击,NotificationCenter,KVO

viewDidLoad

loadData 加载数据,调用一些api

dealloc

destroyEvents 取消事件绑定
destroyViews 释放,销毁视图
destroyFields 释放,销毁引用的变量

didReceiveMemoryWarning

cleanData 释放一些可以释放的资源

额外

enterForeground 进入前台时调用
enterBackground 进入后台时调用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,780评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,424评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,397评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,576评论 0 218
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,997评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,945评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,107评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,850评论 0 208
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,625评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,804评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,285评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,613评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,291评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,164评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,963评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,096评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,886评论 2 278

推荐阅读更多精彩内容

  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,040评论 29 470
  • 1.Difference between shallow copy and deep copy? 浅复制和深复制的...
    用心在飞阅读 974评论 0 9
  • 1.OC里用到集合类是什么? 基本类型为:NSArray,NSSet以及NSDictionary 可变类型为:NS...
    轻皱眉头浅忧思阅读 1,295评论 0 3
  • OC的理解与特性 OC作为一门面向对象的语言,自然具有面向对象的语言特性:封装、继承、多态。它既具有静态语言的特性...
    克鲁德李阅读 413评论 0 0
  • 001画完便不看 我们要积极地记住自己的思维导图,在一定时间内复习,持续长期记忆。 002没有想法继续画 思维过程...
    自由家AU阅读 279评论 2 1