面试题整理(一)

1.堆和栈的区别

栈,是由编译器自动管理,无需我们手工控制;
堆,释放工作由程序员控制,容易产生memory leak(内存泄漏)。

申请大小:
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。

分配方式:

1. 堆都是动态分配的,没有静态分配的堆。
2. 栈有2种分配方式:静态分配和动态分配。

2.死锁问题

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"11111");
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"22222");
    });
    NSLog(@"33333");
}

//死锁原因

  1. dispatch_sync在等待block语句执行完成,而block语句需要在主线程里执行,所以 dispatch_sync 如果在主线程调用就会造成死锁

  2. dispatch_sync是同步的,本身就会阻塞当前线程,也即主线程。而又往主线程里塞进去一个block,所以就会发生死锁。

/**正确方法**/
//async 在主线程中 创建了一个异步线程 加入 全局并发队列,async 不会等待block 执行完成,立即返回
dispatch_async(dispatch_get_global_queue(), ^{
    NSLog(@2);//不会造成死锁;
});

分析这段代码:view DidLoad 在主线程中,也即dispatch_get_main_queue()中,执行到sync时向dispatch_get_main_queue()插入同步threadsync会等到后面的block执行完成才返回。
sync又在主队列里面,是个串行队列,sync是后面才加入的,前面一个是主线程,所以sync想执行block必须等待前一个主线程执行完成,而主线程却在等待sync返回,去执行后续工作,从而造成死锁。

注意: dispatch_sync 和 dispatch_async 区别:
dispatch_async(queue,block) async 异步队列,dispatch_async 函数会立即返回, block会在后台异步执行。
dispatch_sync(queue,block) sync 同步队列,dispatch_sync 函数不会立即返回,即阻塞当前线程,等待 block同步执行完成。

GCD Queue 分为三种:
1.The main queue:主队列,主线程就是在个队列中。
2.Global queues:全局并发队列。
3.用户队列:是用函数 dispatch_queue_create 创建的自定义队列

3.UIImage初始化方法的区别

  • 方法一:
UIImage *image = [UIImage imageNamed:@"test.png"];

这个方法创建的图片是从缓存里面获取的,先在缓存里查看,看是不是有这个图片,没有的话见图片添加到缓存再使用。有的话直接使用缓存里面的。在程序中,如果这个图片要在多个地方使用的话,建议使用这个方法。缺点是:一旦加入到缓存中就一直占用内存,不能被释放掉。

  • 方法二:
//读取本地图片路径
NSString *imagePath=[NSString stringWithFormat:@"%@/Documents/
%@.jpg",NSHomeDirectory(),@"test"];
[UIImage imageWithContentsOfFile:imagePath];

从手机本地读取,比较第一种方式,这个是直接加载图片的,图片不需要的时候,可以release掉。所以建议在使用重复率低的地方使用这种方法。

  • 方法三:
// 下面的这种方式会出现卡线程的情况,所以建议在子线程中操作
// imageWithData: data
NSURL *url = [NSURL URLWithString:@“http://e.picphotos.baidu.com/album/abc.jpg"];
UIImage *image2 = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];

需要注意的是,如果imageWithData:是同步网络请求,如果在主线程直接使用的话,会卡主线程,因此一般不会在主线程中直接使用,而是采用异步网络请求获得data的值。

4. iOS中self.和下划线的区别

1.首先通过self.xxx 通过访问的方法的引用:包含了set和get方法。而通过下划线是获取自己的实例变量,不包含set和get的方法。(回答面试官这一句就行了)

2.self.xxx是对属性的访问;而_xxx是对局部变量的访问。所有被声明为属性的成员,再ios5之前需要使用编译指令@synthesize 来告诉编译器帮助生成属性的getter和setter方法,之后这个指令可以不用认为的指定了,默认情况下编译器会帮助我们生成。
编译器在生成getter,setter方法时是有优先级的,他首先查找当前的类中用户是否定义属性的getter,setter方法,如果有,则编译器会跳过,不会再生成,使用用户定义的方法。也就是说你在使用self.xxx时是调用一个getter方法。
会使引用计数加一,而_xxx不会使用引用技术加一的。

3.所有使用self.xxx是更好的选择,因为这样可以兼容懒加载,同时也避免了使用下滑线的时候忽略了self这个指针,后者容易在BLock中造成循环引用。同时,使用 _是获取不到父类的属性,因为它只是对局部变量的访问。

最后总结:self方法实际上是用了get和set方法间接调用,下划线方法是直接对变量操作。

5. 总结UITableViewCell重用机制

/*
UITableView内部定义了两种数据结构:
NSMutableArray: visiableCells 
NSMutableDictionary:reuseTableCells

其中 visiableCells 保存屏幕上可见的 cell ,而 reuseTableCells 保存可重用的 cells.
*/
NSString* cellIdentifier = @"cellid"

/*
1.在tableView显示之初, reuseTableCells为空。
那么[tableView dequeueReusableCellWithIdentifier:cellIdentifier]返回nil。
*/

/*
2.开始时的cell都是通过 
[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]
来创建,而且cellForRowAtIndexPath:只是调用最大显示cell数的次数。

比如:有100条数据,iPhone一屏最多显示10个cell。
程序最开始显示TableView的情况是: 

创建10次cell,并给cell指定同样的重用标识(当然,可以为不同显示类型的cell指定不同的标识)。
并且10个cell全部都加入到visiableCells数组,reusableTableCells为空。
*/
[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];

//向下拖动tableView,当cell1完全移出屏幕,并且cell11(它也是alloc出来的,原因同上)完全显示出来的时候。
//cell11加入到visiableCells,cell1移出visiableCells,cell1加入到reusableTableCells。  

/*
3.接着向下拖动tableView,因为reusableTableCells中已经有值,所以,当需要显示新的cell,cellForRowAtIndexPath再次被调用的时候,
[tableView dequeueReusableCellWithIdentifier:CellIdentifier]返回cell1。
cell1加入到visiableCells,cell1移出reusableTableCells;
cell2移出visiableCells,cell2加入到reusableTableCells。
之后再需要显示的Cell就可以正常重用了。 
*/

所以整个过程并不难理解,但需要注意正是因为这样的原因:配置Cell的时候一定要注意,对取出的重用的cell做重新赋值,不要遗留老数据。

6.iOS多线程的四种技术方案

  • 如图


    14902857217308.png

7. 假设有一个字符串aabcad,请写一段程序,去掉字符串中不相邻的重复字符串,即上述字符串处理之后的输出结果为:aabcd


NSMutableString * str1 = [[NSMutableString alloc] initWithFormat:@"aabcad"];
    for (int i = 0; i < str1.length - 1; i++) {
        for (int j = i + 1; j < str1.length ; j++) {
            // 由于字符的特殊性  无法使用 字符串 isEqualToString 进行比较 只能转化为ASCII 值进行比较  所以 需要加 unsigined 修饰
           unsigned char a = [str1 characterAtIndex:i];
           unsigned char b = [str1 characterAtIndex:j];
            if (a == b) {
                if (j - i > 1) {
                    // NSRange:  截取字符串   {j, 1} j: 第一个字符开始  1: 截取几个字符
                    NSRange  range = {j, 1};
                   [str1 deleteCharactersInRange:range];
                    j = i--;
                }
            }
        }
    }
    NSLog(@"------ %@-------", str1);

8. iOS中几种数据持久化方案

  • plist文件(属性列表)
  • preference(偏好设置)
  • NSKeyedArchiver(归档)
  • SQLite 3
  • CoreData

假如你不熟练:面试官问常用哪种,就回答SQLite . 问详细的话,就回答上GitHub上面找封装好的工具类来实现存储...

9.iOS传参数的几种方案

  • 1.属性传值
UIViewController *B = [UIViewController new];

B.title = @"B的标题";

[A.navigationController pushViewController:B animated:YES];

通常用于正向传值,适用于A和B相互具有一定关联性。不能用于隔页面传值。而且,需要传值的属性不能是私有属性,也就是说在.h中声明出来的属性才可以传值。

  • 2.Block传值
    使用场景:
    常用于回调,简单的说就是B有一个按钮,当按钮被点击时把点击事件传传给A,并传一个字符串"B被点了"。
//首先在B控制器中声明一个block,参数是一个字符串
@property (nonatomic,copy) void(^block)(NSString *title);

//传值
- (void)buttonClick:(UIButton *)sender
{
    self.block(@"B被点了");
}

//回调代码块
 BController *B = [BController new];

    B.block = ^(NSString *title) {

        //do someThing
        A.title = title;

    };

    [A.navigationController pushViewController:B animated:YES];
    

同样的Block在这里作为属性存在,同属性传值一样,需要两个控制器间具有一定关联性。不能跨页面传值。
如果一定要跨,就要像接力赛一样,A传给B,B传给C这样

  • 3.代理传值
    代理传值和block传值相似,都是将事件分发出去。但是与block的不同在于,代理具有松耦合性,谁想处理事件成为代理即可。

  • 4.通知中心传值
    上面说的代理属于一对一的关系,就好像一夫一妻制。你有需求只能找你的代理(你老婆)。而通知中心属于一对多的,就像村头的喇叭一喊,全村人都能听到。

  • 5.单例传值
    iOS系统中常间的单例模式莫过于UIApplication、 NSNotificationCenter、 NSUserDefaults(常用)

  • 6.数据库传值
    数据库无非在于打开数据库、建表以及基于数据库表的增删改查操作
    这里有一个唐巧大大的FMDB的demo自行学习吧demo点这里

  • 7.NSFileManager
    跟数据库类似,只是将数据写成文件保存在沙盒中。
    需要注意的:
    ( 1 ) 文件路径是否正确
    ( 2 ) 不能保存复杂对象
    相关篇幅还是有点长度的,这里推荐个链接详细了解点这里

  • 8.全局变量传值
    在某个文件的.m文件创建一个全局变量,其他文件只要引用该变量,即可对该变量值进行修改和使用。需要注意,变量名要保证全局唯一。

10.iOS的APP实现相互调起和参数的传值

一、首先为要跳转的App,添加自定义URL协议的Schemesid,很多成熟的App都有固定的Schemesid,下面再说,首先添加自定义URL协议,添加方法这里介绍两种:

  • 第一种:直接在Info.plist里面添加,如图:
14902868774681.png

在这里,URL Schemesitem的值是APP跳转过程中的key,也就是自定义的url协议向iphone注册的key,URL identifier就相当于参数,你可以跳转到你的app的某一个具体功能页面,甚至事件。这里也可以不填写

  • 第二种:可以直接在infoURL types中添加如图:
14902869569022.png

二、实现跳转的代码,在这里使用openURL来实现APP之间的跳转,随着xcode的更新,目前需要添加白名单,过程如下:

  • 第一:添加白名单,在自己的的应用程序的的info.plist中添加LSApplicationQueriesSchemes属性,其类型为数组,然后在数组的下面添加要跳转的appURL Schemeskey
    添加白名单如图:
    14902870096220.png
  • 第二:编写代码实现跳转,这里跳转用的是openurl,跳转的test02app
    如图:
    14902870208780.jpg

无参数的打开url schemestest02app
代码如下:

- (IBAction)skipOtherApp:(UIButton *)sender {

    NSURL* open_URL_A = [NSURL URLWithString:@"test02://"];

    //判断是否是否有can打开应用程序,如果成功就打开
    if ([[UIApplication sharedApplication] canOpenURL:open_URL_A]) {

        NSLog(@"可以打开");

        [[UIApplication sharedApplication] openURL:open_URL_A];
    }
}

三:app在跳转过程中的参数传输,当跳转到url Schemestest02时,将指定的数据传送过去,url Schemestest02的程序在对数据处理(常用的参数传输为:test02登录数据,test02跳转到指定界面等)

(1)参数传递

将上面的代码:

NSURL* open_URL_A = [NSURL URLWithString:@"test02://"];

修改成为:

NSURL* open_URL_A = [NSURL URLWithString:@"test02://name=test01&password=123456"];

这样test01跳转到test02时的传输数据为"name=test01&password=123456",而在test02中处理传递数值的位置为appdelegate.m,在这里添加方法如下:

- (BOOL)application:(UIApplication *)application 
            openURL:(NSURL *)url 
  sourceApplication:(NSString *)sourceApplication 
         annotation:(id)annotation{

/*
 *sour ceAppl i cat i on 从那个app跳转的
 *url 跳转时,openurl中的数据
 *str url 为 test02://name=test01&password=123456 然后对字符串处理
 */
NSString* str_url = [NSString stringWithlContentsOfURL:url 
                                              encoding:kCFStringEncodingUTF8 
                                                 error:nil] ;
    return YES;   
    }

test02 接受参数
(2)从自己的app跳转到AppStore 下载指定的app,具体代码如下:

NSString* urlString = @"itms://itunes.apple.com/gb/app/id391945719?mt=8";
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];

其中id391945719可以改为你指定的appid,当然你也可以将指定app的下载地址的https改为itms就可以了。

11.自动释放池,原理以及如何工作的

  • 1.什么是自动释放池
    自动释放池autorelease poolOC的一种内存自动回收机制.
    当你向一个对象发送一个autorelease消息的时候,cocoa就会将对象的一个引用放入
    到最新的自动释放池中(当前线程栈顶位置),它任然是一个正当的对象,因此自动释放池
    定义的作用域内的其他对象都可以向他发送消息.
  • 2.如何工作
    objective-C是通过一种referring counting(引用计数)的方式管理内存的
    对象在开始分配内存alloc的时候引用计数为1,以后如果有copy,retain的时候
    都会加1,每当releaseautorelease的时候引用计数就会减1,如果一个对象的引
    用计数为0,就会被系统销毁.
    NSAutoreleasePool 就是用来做引用计数的管理工作的,这个东西一般不用你管的
    autoreleaserelease没什么区别,只是引用计数减1的时机不同而已. autorelease
    会在对象的使用真正结束的时候才做引用计数减1.
  • 3.自动释放池的实现原理
    实现原理:自动释放池以栈的形式实现:当你创建一个新的自动释放池时,它将被添加到
    栈顶.当一个对象收到autorelease消息的时候,它被添加到当前线程的处于
    栈顶的的自动释放池中,当自动释放池被回收时,他们就从栈中被删除,并且会
    给池子里面的所有对象都会做一次release操作.
关于自动释放池的内容,后续如果有内容的增加会补上
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容

  • 1.http和https有什么区别? (1)HTTP:超文本传输协议,是短连接,是客户端主动发送请求,服务器作出相...
    Lessin阅读 579评论 0 5
  • 1.Android系统的架构 Android采用层次化系统架构,官方公布的标准架构如下图所示。Android由底层...
    大弃阅读 1,660评论 0 11
  • iOS面试小贴士 ———————————————回答好下面的足够了------------------------...
    不言不爱阅读 1,970评论 0 7
  • 请解释以下代码是什么意思: 资料1资料2资料3 2.NSNtification和KVO的区别和用法是什么?什么时候...
    zhf_Zachariah阅读 921评论 0 3
  • 1、使用NSTimer,需要注意什么? 这里按我的理解就是,主要是涉及runloop了。 一是拖动scrollVi...
    Jt_Self阅读 281评论 0 3