IOS 面试题

本文详细介绍了Objective-C中的关键概念和技术,包括内存管理(如引用计数、ARC)、多线程(GCD、NSOperation、NSThread)、Block、Category、MVC模式、协议、KVO、KVC以及单例模式。此外,还讨论了线程同步、多态性、以及Objective-C中的动态运行时特性。
摘要由CSDN通过智能技术生成

Object-c的类可以多重继承么?可以实现多个接⼝么?Category是什么?重写⼀个类的⽅式⽤继承好还是分类好?为什么?

Object-c的类不可以多重继承;

可以实现多个接⼝,通过实现多个接⼝可以完成C++的多重继承;

Category是类别;

⼀般情况⽤分类好,⽤Category去重写类的⽅法,仅对本Category有效,不会影响到其他类与原有类的关系。

#import 跟#include 有什么区别,@class呢, #import<>跟 #import""⼜什么区别?

#import指令是Object-C针对#include的改进版本,#import确保引用的文件只会被引用一次,这样你就不会产生循环引用。

#import会链入该头文件的全部信息,包括实体变量和方法等;而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑。在头文件中, 一般只需要知道被引用的类的名称就可以了。 不需要知道其内部的实体变量和方法,所以在头文件中一般使用@class来声明这个名称是类的名称。 而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。@class还可以解决循环包含的问题。

#import<>用来包含系统自带的文件,#import""用来包含自定义的文件

属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作⽤,在那种情况下⽤?

readwrite 是可读可写特性;需要⽣成getter⽅法和setter⽅法时

readonly 是只读特性 只会⽣成getter⽅法 不会⽣成setter⽅法 ;不希望属性在类外改变

assign 是赋值特性,setter⽅法将传⼊参数赋值给实例变量;仅设置变量时;

retain 表⽰持有特性,setter⽅法将传⼊参数先保留,再赋值,传⼊参数的retaincount会+1;

copy 表⽰赋值特性,setter⽅法将传⼊对象复制⼀份;需要完全⼀份新的变量时。

nonatomic ⾮原⼦操作,决定编译器⽣成的setter getter是否是原⼦操作,atomic表⽰多线程安全,⼀般使⽤nonatomic

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

在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如: delegate 代理属性。

自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性一般也使用 weak;当然,也可以使用strong。IBOutlet连出来的视图属性为什么可以被设置成weak?    因为父控件的subViews数组已经对它有一个强引用。

不同点:assign 可以用非 OC 对象,而 weak 必须用于 OC 对象。weak 表明该属性定义了一种“非拥有关系”。在属性所指的对象销毁时,属性值会自动清空(nil)。

@synthesize 和 @dynamic 分别有什么作用?

@property有两个对应的词,一个是@synthesize(合成实例变量),一个是@dynamic。

如果@synthesize和@dynamic都没有写,那么默认的就是 @synthesize var = _var;

在类的实现代码里通过 @synthesize 语法可以来指定实例变量的名字。(@synthesize var = _newVar;)

@synthesize 的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。

@dynamic 告诉编译器,属性的setter与getter方法由用户自己实现,不自动生成(如,@dynamic var)。

写⼀个setter⽅法⽤于完成@property (nonatomic,retain)NSString name,写⼀个setter⽅法⽤于完成@property(nonatomic,copy)NSString name

@property (nonatomic,retain)NSString name

-(void) setName:(NSString*) str{   

    [str retain];   

    [name release];   

    name = str;

}

@property(nonatomic,copy)NSString name

-(void)setName:(NSString *)str{   

    id t = [str copy];   

    [name release];   

    name = t;

}

对于语句NSString*obj = [[NSData alloc] init]; obj在编译时和运⾏时分别时什么类型的对象?

答: 编译时是NSString的类型;运⾏时是NSData类型的对象

常见的object-c的数据类型有那些, 和C的基本数据类型有什么区别?如:NSInteger和int

答:object-c的数据类型有NSString,NSNumber,NSArray,NSMutableArray,NSData等等,这些都是class,创建后便是对象,⽽C语⾔的基本数据类型int,只是⼀定字节的内存空间,⽤于存放数值;NSInteger是基本数据类型,并不是NSNumber的⼦类,当然也不是NSObject的⼦类。NSInteger是基本数据类型Int或者Long的别名(NSInteger的定义typedef long NSInteger),它的区别在于,NSInteger会根据系统是32位还是64位来决定是本⾝是int还是Long。

id 声明的对象有什么特性?

答:Id 声明的对象具有运⾏时的特性,即可以指向任意类型的objcetive-c的对象;

Objective-C如何对内存管理的,说说你的看法和解决⽅法?

答:Objective-C的内存管理主要有三种⽅式ARC(⾃动内存计数)、⼿动内存计数、内存池。

(Garbage Collection)⾃动内存计数:这种⽅式和java类似,在你的程序的执⾏过程中。始终有⼀个⾼⼈在背后准确地帮你收拾垃圾,你不⽤考虑它什么时候开始⼯作,怎样⼯作。你只需要明⽩,我申请了⼀段内存空间,当我不再使⽤从⽽这段内存成为垃圾的时候,我就彻底的把它忘记掉,反正那个⾼⼈会帮我收拾垃圾。遗憾的是,那个⾼⼈需要消耗⼀定的资源,在携带设备⾥⾯,资源是紧俏商品所以iPhone不⽀持这个功能。所以“Garbage Collection”不是本⼊门指南的范围,对“Garbage Collection”内部机制感兴趣的同学可以参考⼀些其他的资料,不过说⽼实话“Garbage Collection”不⼤适合适初学者研究。解决: 通过alloc – initial⽅式创建的, 创建后引⽤计数+1, 此后每retain⼀次引⽤计数+1,那么在程序中做相应次数的release就好了。

(Reference Counted)⼿动内存计数:就是说,从⼀段内存被申请之后,就存在⼀个变量⽤于保存这段内存被使⽤的次数,我们暂时把它称为计数器,当计数器变为0的时候,那么就是释放这段内存的时候。⽐如说,当在程序A⾥⾯⼀段内存被成功申请完成之后,那么这个计数器就从0变成1(我们把这个过程叫做alloc),然后程序B也需要使⽤这个内存,那么计数器就从1变成了2(我们把这个过程叫做retain)。紧接着程序A不再需要这段内存了,那么程序A就把这个计数器减1(我们把这个过程叫做release);程序B也不再需要这段内存的时候,那么也把计数器减1(这个过程还是release)。当系统(也就是Foundation)发现这个计数器变 成员了0,那么就会调⽤内存回收程序把这段内存回收(我们把这个过程叫做dealloc)。顺便提⼀句,如果没有Foundation,那么维护计数器,释放内存等等⼯作需要你⼿⼯来完成。解决:⼀般是由类的静态⽅法创建的, 函数名中不会出现alloc或init字样, 如[NSString string]和[NSArray arrayWithObject:],创建后引⽤计数+0, 在函数出栈后释放, 即相当于⼀个栈上的局部变量。当然也可以通过retain延长对象的⽣存期。

(NSAutoRealeasePool)内存池:可以通过创建和释放内存池控制内存申请和回收的时机。

解决:是由autorelease加⼊系统内存池, 内存池是可以嵌套的, 每个内存池都需要有⼀个创建释放对, 就像main函数中写的⼀样. 使⽤也很简单, ⽐如[[[NSString alloc]initialWithFormat:@”Hey you!”] autorelease], 即将⼀个NSString对象加⼊到最内层的系统内存池, 当我们释放这个内存池时, 其中的对象都会被释放.

原⼦(atomic)跟⾮原⼦(non-atomic)属性有什么区别?

atomic提供多线程安全。是防⽌在写未完成的时候被另外⼀个线程读取,造成数据错误

non-atomic:在⾃⼰管理内存的环境中,解析的访问器保留并⾃动释放返回的值,如果指定了 nonatomic ,那么访问器只是简单地返回这个值。

看下⾯的程序,第⼀个NSLog会输出什么?这时str的retainCount是多少?第⼆个和第三个呢? 为什么?

NSMutableArray* ary = [[NSMutableArray array] retain]; // [str retainCount]=1

NSString *str = [NSString stringWithFormat:@"test"];

[str retain]; // [str retainCount]=1+1=2

[ary addObject:str]; // [str retainCount]=2+1=3

NSLog(@”%@%d”,str,[str retainCount]); // test, 3

[str retain]; // [str retainCount]=3+1=4

[str release]; // [str retainCount]=4-1=4

[str release]; // [str retainCount]=3-1=2

NSLog(@”%@%d”,str,[str retainCount]); // test, 2

[ary removeAllObjects]; // [str retainCount]=2-1=1

NSLog(@”%@%d”,str,[str retainCount] // test, 1

str的retainCount创建+1,retain+1,加⼊数组⾃动+1 3

retain+1,release-1,release-1 2

数组删除所有对象,所有数组内的对象⾃动-1 1

内存管理的⼏条原则时什么?按照默认法则那些关键字⽣成的对象需要⼿动释放?在和property结合的时候怎样有效的避免内存泄露?

谁申请,谁释放,遵循Cocoa Touch的使⽤原则;内存管理主要要避免“过早释放”和“内存泄漏”,对于“过早释放”需要注意@property设置特性时,⼀定要⽤对特性关键字,对于“内存泄漏”,⼀定要申请了要负责释放,要细⼼。关键字alloc 或new ⽣成的对象需要⼿动释放;设置正确的property属性,对于retain需要在合适的地⽅释放。

如何对iOS设备进⾏性能测试?

Profile; Instruments ;Time Profiler

Object C中创建线程的⽅法是什么?如果在主线程中执⾏代码,⽅法是什么?如果想延时执⾏代码、⽅法⼜是什么?

线程创建有三种⽅法:使⽤NSThread创建、使⽤GCD的dispatch、使⽤⼦类化的NSOperation,然后将其加⼊NSOperationQueue

//在主线程执⾏代码,⽅法是:

- (void)performSelectorOnMainThread;

// 如果想延时执⾏代码可以⽤:

- (void)performSelector:(SEL)aSelector

              onThread:(NSThread *)thr

            withObject:(id)arg

          waitUntilDone:(BOOL)wait;

MVC设计模式是什么? 你还熟悉什么设计模式?

设计模式:并不是⼀种新技术,⽽是⼀种编码经验,使⽤⽐如java中的接⼝,iphone中的协议,继承关系等基本⼿段,⽤⽐较成熟的逻辑去处理某⼀种类型的事情,总结为所谓设计模式。⾯向对象中,java已经归纳了23种设计模式。m设计模式 :模型,视图,控制器,可以将整个应⽤程序在思想上分成三⼤块,对应是的数据的存储或处理,前台的显⽰,业务逻辑的控制。 Iphone本⾝的设计思想就是遵循mvc设计模式。其不属于23种设计模式范畴。

代理模式:代理模式给某⼀个对象提供⼀个代理对象,并由代理对象控制对源对象的引⽤。⽐如⼀个⼯⼚⽣产了产品,并不想直接卖给⽤户,⽽是搞了很多代理商,⽤户可以直接找代理商买东西,代理商从⼯⼚进货.常见的如QQ的⾃动回复就属于代理拦截,代理模式在iphone中得到⼴泛应⽤。

单例模式:说⽩了就是⼀个类不通过alloc⽅式创建对象,⽽是⽤⼀个静态⽅法返回这个类的对象。系统只需要拥有⼀个的全局对象,这样有利于我们协调系统整体的⾏为,⽐如想获得[UIApplication sharedApplication];任何地⽅调⽤都可以得到 UIApplication的对象,这个对象是全局唯⼀的。

观察者模式: 当⼀个物体发⽣变化时,会通知所有观察这个物体的观察者让其做出反应。实现起来⽆⾮就是把所有观察者的对象给这个物体,当这个物体的发⽣改变,就会调⽤遍历所有观察者的对象调⽤观察者的⽅法从⽽达到通知观察者的⽬的。

⼯⼚模式:

publicclassFactory{

    publicstaticSample creator(int which){

        if(which=="1")

            return new SampleA();

        elseif(which=="2")

            return new SampleB();

    }

}

浅复制和深复制的区别?

浅层复制:只复制指向对象的指针,⽽不复制引⽤对象本⾝。

深层复制:复制引⽤对象本⾝。意思就是说我有个A对象,复制⼀份后得到A_copy对象后,对于浅复制来说,A和A_copy指向的是同⼀个内存资源,复制的只不过是是⼀个指针,对象本⾝资源还是只有⼀份,那如果我们对A_copy执⾏了修改操作,那么发现A引⽤的对象同样被修改,这其实违背了我们复制拷贝的⼀个思想。深复制就好理解了,内存中存在了两份独⽴对象本⾝。⽤⽹上⼀哥们通俗的话讲就是:浅复制好⽐你和你的影⼦,你完蛋,你的影⼦也完蛋。深复制好⽐你和你的克隆⼈,你完蛋,你的克隆⼈还活着。

类别的作⽤?继承和类别在实现中有何区别?

答:category 可以在不获悉,不改变原来代码的情况下往⾥⾯添加新的⽅法,只能添加,不能删除修改,并且如果类别和原来类中的⽅法产⽣名称冲突,则类别将覆盖原来的⽅法,因为类别具有更⾼的优先级。

类别主要有3个作⽤:

将类的实现分散到多个不同⽂件或多个不同框架中。

创建对私有⽅法的前向引⽤。

向对象添加⾮正式协议。

继承可以增加,修改或者删除⽅法,并且可以增加属性。

类别和类扩展的区别。

category和extensions的不同在于 后者可以添加属性。另外后者添加的⽅法是必须要实现的。extensions可以认为是⼀个私有的Category。

oc中的协议和java中的接⼝概念有何不同?

OC中的代理有2层含义,官⽅定义为 formal和informal protocol。前者和接⼝⼀样。informal protocol中的⽅法属于设计模式考虑范畴,不是必须实现的,但是如果有实现,就会改变类的属性。其实关于正式协议,类别和⾮正式协议我很早前学习的时候⼤致看过,也写在了学习教程⾥“⾮正式协议概念其实就是类别的另⼀种表达⽅式“这⾥有⼀些你可能希望实现的⽅法,你可以使⽤他们更好的完成⼯作”。这个意思是,这些是可选的。⽐如我门要⼀个更好的⽅法,我们就会申明⼀个这样的类别去实现。然后你在后期可以直接使⽤这些更好的⽅法。这么看,总觉得类别这玩意⼉有点像协议的可选协议。”现在来看,其实protocal已经开始对两者都统⼀和规范起来操作,因为资料中说“⾮正式协议使⽤interface修饰“,现在我们看到协议中两个修饰词:“必须实现(@requied)”和“可选实现(@optional)”。

什么是KVOKVC?

KVC:键 – 值编码是⼀种间接访问对象的属性使⽤字符串来标识属性,⽽不是通过调⽤存取⽅法,直接或通过实例变量访问的机制。很多情况下可以简化程序代码。apple⽂档其实给了⼀个很好的例⼦。

KVO:键值观察机制,他提供了观察某⼀属性变化的⽅法,极⼤的简化了代码。具体⽤到过的⼀个地⽅是对于按钮点击变化状态的的监控。

⽐如我⾃定义的⼀个button:

[self addObserver:self forKeyPath:@"highlighted" options:0 context:nil];

#pragma mark KVO

- (void) observeValueForKeyPath:(NSString *)keyPath

                      ofObject:(id)object

                        change:(NSDictionary *)change

                        context:(void*)context{

                            if([keyPath isEqualToString:@"highlighted"] ) {

                                [self setNeedsDisplay];

                            }

                        }

对于系统是根据keypath去取的到相应的值发⽣改变,理论上来说是和kvc机制的道理是⼀样的。对于kvc机制如何通过key寻找到value:当通过KVC调⽤对象时,⽐如:[self valueForKey:@"someKey"]时,程序会⾃动试图通过⼏种不同的⽅式解析这个调⽤。⾸先查找对象是否带有 someKey 这个⽅法,如果没找到,会继续查找对象是否带有someKey这个实例变量(iVar),如果还没有找到,程序会继续试图调⽤ -(id) valueForUndefinedKey:这个⽅法。如果这个⽅法还是没有被实现的话,程序会抛出⼀个NSUndefinedKeyException异常错误。(注:Key-Value Coding查找⽅法的时候,不仅仅会查找someKey这个⽅法,还会查找getsomeKey这个⽅法,前⾯加⼀个get,或者_someKey以及_getsomeKey这⼏种形式。同时,查找实例变量的时候也会不仅仅查找someKey这个变量,也会查找_someKey这个变量是否存在。)设计valueForUndefinedKey:⽅法的主要⽬的是当你使⽤-(id)valueForKey⽅法从对象中请求值时,对象能够在错误发⽣前,有最后的机会响应这个请求。这样做有很多好处,下⾯的两个例⼦说明了这样做的好处。来⾄cocoa,这个说法应该挺有道理。因为我们知道button却是存在⼀个highlighted实例变量.因此为何上⾯我们只是add⼀个相关的keypath就⾏了,可以按照kvc查找的逻辑理解,就说的过去了。

代理的作⽤?

答:代理的⽬的是改变或传递控制链。允许⼀个类在某些特定时刻通知到其他类,⽽不需要获取到那些类的指针。可以减少框架复杂度。另外⼀点,代理可以理解为java中的回调监听机制的⼀种类似。

oc中可修改和不可以修改类型。

答:可修改不可修改的集合类。这个我个⼈简单理解就是可动态添加修改和不可动态添加修改⼀样。⽐如NSArray和NSMutableArray。前者在初始化后的内存空间就是固定不可变的,后者可以添加等,可以动态申请新的内存空间。

我们说的oc是动态运⾏时语⾔是什么意思?

答:多态。 主要是将数据类型的确定由编译时,推迟到了运⾏时。这个问题其实浅涉及到两个概念,运⾏时和多态。简单来说,运⾏时机制使我们直到运⾏时才去决定⼀个对象的类别,以及调⽤该类别对象指定⽅法。

多态:不同对象以⾃⼰的⽅式响应相同的消息的能⼒叫做多态。意思就是假设⽣物类(life)都⽤有⼀个相同的⽅法-eat;

那⼈类属于⽣物,猪也属于⽣物,都继承了life后,实现各⾃的eat,但是调⽤是我们只需调⽤各⾃的eat⽅法。也就是不同的对象以⾃⼰的⽅式响应了相同的消息(响应了eat这个选择器)。因此也可以说,运⾏时机制是多态的基础

通知和协议的不同之处?

答:协议有控制链(has-a)的关系,通知没有。⾸先我⼀开始也不太明⽩,什么叫控制链(专业术语了~)。但是简单分析下通知和代理的⾏为模式,我们⼤致可以有⾃⼰的理解简单来说,通知的话,它可以⼀对多,⼀条消息可以发送给多个消息接受者。代理按我们的理解,到不是直接说不能⼀对多,⽐如我们知道的明星经济代理⼈,很多时候⼀个经济⼈负责好⼏个明星的事务。只是对于不同明星间,代理的事物对象都是不⼀样的,⼀⼀对应,不可能说明天要处理A明星要⼀个发布会,代理⼈发出处理发布会的消息后,别称B的发布会了。但是通知就不⼀样,他只关⼼发出通知,⽽不关⼼多少接收到感兴趣要处理。因此控制链(has-a从英语单词⼤致可以看出,单⼀拥有和可控制的对应关系。

什么是推送消息?

答:推送通知更是⼀种技术。简单点就是客户端获取资源的⼀种⼿段。普通情况下,都是客户端主动的pull。推送则是服务器端主动push。 测试push的实现可以查看该博⽂。

关于多态性

答:多态,⼦类指针可以赋值给⽗类。这个题⽬其实可以出到⼀切⾯向对象语⾔中,因此关于多态,继承和封装基本最好都有个⾃我意识的理解,也并⾮⼀定要把书上资料上写的能背出来

对于单例的理解

答:在objective-c中要实现⼀个单例类,⾄少需要做以下四个步骤:

为单例对象实现⼀个静态实例,并初始化,然后设置成nil,

实现⼀个实例构造⽅法检查上⾯声明的静态实例是否为nil,如果是则新建并返回⼀个本类的实例,

重写allocWithZone⽅法,⽤来保证其他⼈直接使⽤alloc和init试图获得⼀个新实⼒的时候不产⽣⼀个新实例,

适当实现allocWitheZone,copyWithZone,release和autorelease。

说说响应链

答: 事件响应链。包括点击事件,画⾯刷新事件等。在视图栈内从上⾄下,或者从下之上传播。可以说点事件的分发,传递以及处理。具体可以去看下touch事件这块。因为问的太抽象化了严重怀疑题⽬出到越后⾯就越笼统。可以从责任链模式,来讲通过事件响应链处理,其拥有的扩展性

frame和bounds有什么不同?

frame指的是:该view在⽗view坐标系统中的位置和⼤⼩。(参照点是⽗亲的坐标系统)

bounds指的是:该view在本⾝坐标系统中 的位置和⼤⼩。(参照点是本⾝坐标系统)

⽅法和选择器有何不同?

答:selector是⼀个⽅法的名字,method是⼀个组合体,包含了名字和实现。详情可以看apple⽂档。

OC垃圾回收机制?

答: OC2.0有Garbage collection,但是iOS平台不提供。⼀般我们了解的objective-c对于内存管理都是⼿动操作的,但是也有⾃动释放池。但是差了⼤部分资料,貌似不要和arc机制搞混就好了。

iOS多线程技术有哪几种方式?

答:pthread、NSThread、GCD、NSOperation

GCD 与 NSOperation 的区别:

GCD 和 NSOperation 都是用于实现多线程:   

GCD 基于C语言的底层API,GCD主要与block结合使用,代码简洁高效。   

NSOperation 属于Objective-C类,是基于GCD更高一层的封装。复杂任务一般用NSOperation实现。

写出使用GCD方式从子线程回到主线程的方法代码

dispatch_sync(dispatch_get_main_queue(), ^{

});

如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)

// 使用Dispatch Group追加block到Global Group Queue,这些block如果全部执行完毕,就会执行Main Dispatch Queue中的结束处理的block。

// 创建队列组

dispatch_group_t group = dispatch_group_create();

// 获取全局并发队列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_group_async(group, queue, ^{   //*加载图片1 *//});

dispatch_group_async(group, queue, ^{//加载图片2 *//})

;dispatch_group_async(group, queue, ^{ //加载图片3 *// });

// 当并发队列组中的任务执行完毕后才会执行这里的代码

dispatch_group_notify(group, dispatch_get_main_queue(), ^{    // 合并图片});

dispatch_barrier_async(栅栏函数)的作用是什么?

// 函数定义:

dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);

// 作用:

// 1.在它前面的任务执行结束后它才执行,它后面的任务要等它执行完成后才会开始执行。

// 2.避免数据竞争

// 1.创建并发队列

dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);

// 2.向队列中添加任务

dispatch_async(queue, ^{ 

    // 1.2是并行的   

    NSLog(@"任务1, %@",[NSThread currentThread]);

});

dispatch_async(queue, ^{   

    NSLog(@"任务2, %@",[NSThread currentThread]);

});

dispatch_barrier_async(queue, ^{   

    NSLog(@"任务 barrier, %@", [NSThread currentThread]);

});

dispatch_async(queue, ^{ 

    // 这两个是同时执行的   

    NSLog(@"任务3, %@",[NSThread currentThread]);

});

dispatch_async(queue, ^{   

    NSLog(@"任务4, %@",[NSThread currentThread]);

});

// 输出结果: 任务1 任务2 ——》 任务 barrier ——》任务3 任务4

// 其中的任务1与任务2,任务3与任务4 由于是并行处理先后顺序不定。

以下代码运行结果如何?

- (void)viewDidLoad {   

    [super viewDidLoad];   

    NSLog(@"1");   

    dispatch_sync(dispatch_get_main_queue(), ^{       

        NSLog(@"2");   

    });   

    NSLog(@"3");

}

// 只输出:1。(主线程死锁)

NSOperation queue?

答:存放NSOperation的集合类。操作和操作队列,基本可以看成java中的线程和线程池的概念。⽤于处理ios多线程开发的问题。⽹上部分资料提到⼀点是,虽然是queue,但是却并不是带有队列的概念,放⼊的操作并⾮是按照严格的先进现出。这边⼜有个疑点是,对于队列来说,先进先出的概念是Afunc添加进队列,Bfunc紧跟着也进⼊队列,Afunc先执⾏这个是必然的,但是Bfunc是等Afunc完全操作完以后,B才开始启动并且执⾏,因此队列的概念离乱上有点违背了多线程处理这个概念。但是转念⼀想其实可以参考银⾏的取票和叫号系统。因此对于A⽐B先排队取票但是B率先执⾏完操作,我们亦然可以感性认为这还是⼀个队列。但是后来看到⼀票关于这操作队列话题的⽂章,其中有⼀句提到“因为两个操作提交的时间间隔很近,线程池中的线程,谁先启动是不定的。”瞬间觉得这个queue名字有点忽悠⼈了,还不如pool~综合⼀点,我们知道他可以⽐较⼤的⽤处在于可以帮助多线程编程就好了。

什么是延迟加载?

答:懒汉模式,只在⽤到的时候才去初始化。也可以理解成延时加载。我觉得最好也最简单的⼀个列⼦就是tableView中图⽚的加载显⽰了。⼀个延时载,避免内存过⾼,⼀个异步加载,避免线程堵塞。

是否在⼀个视图控制器中嵌⼊两个tableview控制器?

答:⼀个视图控制只提供了⼀个View视图,理论上⼀个tableViewController也不能放吧,只能说可以嵌⼊⼀个tableview视图。当然,题⽬本⾝也有歧义,如果不是我们定性思维认为的UIViewController,⽽是宏观的表⽰视图控制者,那我们倒是可以把其看成⼀个视图控制者,它可以控制多个视图控制器,⽐如TabbarController那样的感觉。

⼀个tableView是否可以关联两个不同的数据源?你会怎么处理?

答:⾸先我们从代码来看,数据源如何关联上的,其实是在数据源关联的代理⽅法⾥实现的。因此我们并不关⼼如何去关联他,他怎因此我们并不关⼼如何去关联他,他怎么关联上,⽅法只是让我返回根据⾃⼰的需要去设置如相关的数据源。因此,我觉得可以设置多个数据源啊,但是有个问题是,你这是想⼲嘛呢?想让列表如何显⽰,不同的数据源分区块显⽰?

什么时候使⽤NSMutableArray,什么时候使⽤NSArray?

答:当数组在程序运⾏时,需要不断变化的,使⽤NSMutableArray,当数组在初始化后,便不再改变的,使⽤NSArray。需要指出的是,使⽤NSArray只表明的是该数组在运⾏时不发⽣改变,即不能往NSAarry的数组⾥新增和删除元素,但不表明其数组內的元素的内容不能发⽣改变。NSArray是线程安全的,NSMutableArray不是线程安全的,多线程使⽤到NSMutableArray需要注意。

给出委托⽅法的实例,并且说出UITableVIew的Data Source⽅法

答:CocoaTouch框架中⽤到了⼤量委托,其中UITableViewDelegate就是委托机制的典型应⽤,是⼀个典型的使⽤委托来实现适配器模式,其中UITableViewDelegate协议是⽬标,tableview是适配器,实现UITableViewDelegate协议,并将⾃⾝设置为talbeview的delegate的对象,是被适配器,⼀般情况下该对象是UITableViewController。UITableVIew的Data Source⽅法有

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

在应⽤中可以创建多少autorelease对象,是否有限制?

答案:⽆限制

如果我们不创建内存池,是否有内存池提供给我们?

答:界⾯线程维护着⾃⼰的内存池,⽤户⾃⼰创建的数据线程,则需要创建该线程的内存池

什么时候需要在程序中创建内存池?

答:⽤户⾃⼰创建的数据线程,则需要创建该线程的内存池

类NSObject的那些⽅法经常被使⽤?

答:NSObject是Objetive-C的基类,其由NSObject类及⼀系列协议构成。其中类⽅法alloc、class、 description 对象⽅法init、dealloc、– performSelector:withObject:afterDelay:等经常被使⽤

什么是简便构造⽅法?

答:简便构造⽅法⼀般由CocoaTouch框架提供,如NSNumber的

+ (NSNumber *)numberWithBool:(BOOL)value;

+ (NSNumber *)numberWithChar:(char)value;

+ (NSNumber *)numberWithDouble:(double)value;

+ (NSNumber *)numberWithFloat:(float)value;

+ (NSNumber *)numberWithInt:(int)value;

Foundation下⼤部分类均有简便构造⽅法,我们可以通过简便构造⽅法,获得系统给我们创建好的对象,并且不需要⼿动释放。

如何使⽤Xcode设计通⽤应⽤?

答:使⽤MVC模式设计应⽤,其中Model层完成脱离界⾯,即在Model层,其是可运⾏在任何设备上,在controller层,根据iPhone与iPad(独有UISplitViewController)的不同特点选择不同的viewController对象。在View层,可根据现实要求,来设计,其中以xib⽂件设计时,其设置其为universal。

UIView的动画效果有那些?

答:有很多,如

UIViewAnimationOptionCurveEaseInOut

UIViewAnimationOptionCurveEaseIn

UIViewAnimationOptionCurveEaseOut

UIViewAnimationOptionTransitionFlipFromLeft

UIViewAnimationOptionTransitionFlipFromRight

UIViewAnimationOptionTransitionCurlUp

UIViewAnimationOptionTransitionCurlDown

在iPhone应⽤中如何保存数据?

答:有以下⼏种保存机制:

1).通过web服务,保存在服务器上

2).通过NSCoder固化机制,将对象保存在⽂件中

3).通过SQlite或CoreData保存在⽂件中

什么是coredata?

答:coredata是苹果提供⼀套数据保存框架,其基于SQlite

什么是NSManagedObject模型?

答:NSManagedObject是NSObject的⼦类 ,也是coredata的重要组成部分,它是⼀个通⽤的类,实现了core data 模型层所需的基本功能,⽤户可通过⼦类化NSManagedObject,建⽴⾃⼰的数据模型。

什么是NSManagedobjectContext?

答:NSManagedobjectContext对象负责应⽤和数据库之间的交互。

和coredata⼀起有哪⼏种持久化存储机制?

答:存⼊到⽂件、 存⼊到NSUserDefaults(系统plist⽂件中)、存⼊到Sqlite⽂件数据库

谈谈对Block 的理解?并写出⼀个使⽤Block执⾏UIVew动画?

答:Block是可以获取其他函数局部变量的匿名函数,其不但⽅便开发,并且可以⼤幅提⾼应⽤的执⾏效率(多核⼼CPU可直接处理Block指令)

[UIView transitionWithView:self.view duration:0.2

                  options:UIViewAnimationOptionTransitionFlipFromLeft

                animations:^{

                    [[blueViewController view] removeFromSuperview];

                    [[self view] insertSubview:yellowViewController.view atIndex:0];

                } completion:NULL];

写出上⾯代码的Block的定义。

// animations block

typedef void(^animations) (void);

// completion block

typedef void(^completion) (BOOL finished);

做过的项⽬是否涉及⽹络访问功能,使⽤什么对象完成⽹络功能?

答:ASIHTTPRequest与NSURLConnection

简单介绍下NSURLConnection类及+ sendSynchronousRequest:returningResponse:error:与– initWithRequest:delegate:两个⽅法的区别?

答: NSURLConnection主要⽤于⽹络访问,其中+ sendSynchronousRequest:returningResponse:error:是同步访问数据,即当前线程会阻塞,并等待request的返回的response,⽽– initWithRequest:delegate:使⽤的是异步加载,当其完成⽹络访问后,会通过delegate回到主线程,并其委托的对象。

多线程是什么

答: 多线程是个复杂的概念,按字⾯意思是同步完成多项任务,提⾼了资源的使⽤效率,从硬件、操作系统、应⽤软件不同的⾓度去看,多线程被赋予不同的内涵,对于硬件,现在市⾯上多数的CPU都是多核的,多核的CPU运算多线程更为出⾊;从操作系统⾓度,是多任务,现在⽤的主流操作系统都是多任务的,可以⼀边听歌、⼀边写博客;对于应⽤来说,多线程可以让应⽤有更快的回应,可以在⽹络时,同时响应⽤户的触摸操作。在iOS应⽤中,对多线程最初的理解,就是并发,它的含义是原来先做烧⽔,再摘菜,再炒菜的⼯作,会变成烧⽔的同时去摘菜,最后去炒菜。

iOS 中的多线程

答: iOS中的多线程,是Cocoa框架下的多线程,通过Cocoa的封装,可以让我们更为⽅便的使⽤线程,做过C++的同学可能会对线程有更多的理解,⽐如线程的创⽴,信号量、共享变量有认识,Cocoa框架下会⽅便很多,它对线程做了封装,有些封装,可以让我们创建的对象,本⾝便拥有线程,也就是线程的对象化抽象,从⽽减少我们的⼯程,提供程序的健壮性。

GCD是(Grand Central Dispatch)的缩写 ,从系统级别提供的⼀个易⽤地多线程类库,具有运⾏时的特点,能充分利⽤多核⼼硬件。GCD的API接⼝为C语⾔的函数,函数参数中多数有Block,关于Block的使⽤参看这⾥,为我们提供强⼤的“接⼝”,对于GCD的使⽤参见本⽂

NSOperation与Queue

NSOperation是⼀个抽象类,它封装了线程的细节实现,我们可以通过⼦类化该对象,加上NSQueue来同⾯向对象的思维,管理多线程程序。具体可参看这⾥:⼀个基于NSOperation的多线程⽹络访问的项⽬。

NSThread

NSThread是⼀个控制线程执⾏的对象,它不如NSOperation抽象,通过它我们可以⽅便的得到⼀个线程,并控制它。但NSThread的线程之间的并发控制,是需要我们⾃⼰来控制的,可以通过NSCondition实现。参看 iOS多线程编程之NSThread的使⽤

其他多线程

在Cocoa的框架下,通知、Timer和异步函数等都有使⽤多线程,(待补充).

在项⽬什么时候选择使⽤GCD,什么时候选择NSOperation?

答: 项⽬中使⽤NSOperation的优点是NSOperation是对线程的⾼度抽象,在项⽬中使⽤它,会使项⽬的程序结构更好,⼦类化NSOperation的设计思路,是具有⾯向对象的优点(复⽤、封装),使得实现是多线程⽀持,⽽接⼝简单,建议在复杂项⽬中使⽤。项⽬中使⽤GCD的优点是GCD本⾝⾮常简单、易⽤,对于不复杂的多线程操作,会节省代码量,⽽Block参数的使⽤,会是代码更为易读,建议在简单项⽬中使⽤。

什么是block

答: 对于闭包(block),有很多定义,其中闭包就是能够读取其它函数内部变量的函数,这个定义即接近本质⼜较好理解。对于刚接触Block的同学,会觉得有些绕,因为我们习惯写这样的程序main(){ funA();} funA(){funB();} funB(){……}; 就是函数main调⽤函数A,函数A调⽤函数B… 函数们依次顺序执⾏,但现实中不全是这样的,例如项⽬经理M,⼿下有3个程序员A、B、C,当他给程序员A安排实现功能F1时,他并不等着A完成之后,再去安排B去实现F2,⽽是安排给A功能F1,B功能F2,C功能F3,然后可能去写技术⽂档,⽽当A遇到问题时,他会来找项⽬经理M,当B做完时,会通知M,这就是⼀个异步执⾏的例⼦。在这种情形下,Block便可⼤显⾝⼿,因为在项⽬经理M,给A安排⼯作时,同时会告诉A若果遇到困难,如何能找到他报告问题(例如打他⼿机号),这就是项⽬经理M给A的⼀个回调接⼝,要回掉的操作,⽐如接到电话,百度查询后,返回⽹页内容给A,这就是⼀个Block,在M交待⼯作时,已经定义好,并且取得了F1的任务号(局部变量),却是在当A遇到问题时,才调⽤执⾏,跨函数在项⽬经理M查询百度,获得结果后回调该block。

block 实现原理

答: Objective-C是对C语⾔的扩展,block的实现是基于指针和函数指针。从计算语⾔的发展,最早的goto,⾼级语从计算语⾔的发展,最早的goto,⾼级语⾔的指针,到⾯向对象语⾔的block,从机器的思维,⼀步步接近⼈的思维,以⽅便开发⼈员更为⾼效、直接的描述出现实的逻辑(需求)。使⽤实例:

// cocoaTouch框架下动画效果的Block的调⽤使⽤typed声明block

typedef void(^didFinishBlock) (NSObject *ob);

// 这就声明了⼀个didFinishBlock类型的block,然后便可⽤

@property(nonatomic,copy) didFinishBlock finishBlock;

声明⼀个blokc对象,注意对象属性设置为copy,接到block 参数时,便会⾃动复制⼀份。__block是⼀种特殊类型,使⽤该关键字声明的局部变量,可以被block所改变,并且其在原函数中的值会被改变。

关于block

答: ⾯试时,⾯试官会先问⼀些,是否了解block,是否使⽤过block,这些问题相当于开场⽩,往往是下⾯⼀系列问题的开始,所以⼀定要如实根据⾃⼰的情况回答。

1). 使⽤block和使⽤delegate完成委托模式有什么优点?

⾸先要了解什么是委托模式,委托模式在iOS中⼤量应⽤,其在设计模式中是适配器模式中的对象适配器,Objective-C中使⽤id类型指向⼀切对象,使委托模式更为简洁。了解委托模式的细节:

iOS设计模式—-委托模式

使⽤block实现委托模式,其优点是回调的block代码块定义在委托对象函数内部,使代码更为紧凑;

适配对象不再需要实现具体某个protocol,代码更为简洁。

block反向传值

在控制器间传值可以使用代理或者block,使用block相对来说简洁。

在前一个控制器的touchesBegan:方法内实现如下代码。

// OneViewController.m

TwoViewController *twoVC = [[TwoViewController alloc] init];

twoVC.valueBlcok = ^(NSString *str) {

    NSLog(@"OneViewController拿到值:%@", str);

};

[self presentViewController:twoVC animated:YES completion:nil];

// TwoViewController.h (在.h文件中声明一个block属性)

@property (nonatomic ,strong) void(^valueBlcok)(NSString *str);

// TwoViewController.m (在.m文件中实现方法)

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    // 传值:调用block

    if (_valueBlcok) {

        _valueBlcok(@"123456");

    }

}

写一个完整的代理,包括声明、实现

// 创建

@protocol MyDelagate

@required

-(void)eat:(NSString *)foodName;

@optional

-(void)run;

@end

//  声明 .h

@interface person: NSObject<MyDelagate>

@end

//  实现 .m

@implementation person

- (void)eat:(NSString *)foodName {   

    NSLog(@"吃:%@!", foodName);

}

- (void)run { 

    NSLog(@"run!");

}

@end

写一个单例模式

+ (instancetype)sharedData { 

    static dispatch_once_t onceToken; 

    dispatch_once(&onceToken, ^{     

        _instance = [[self alloc] init]; 

    }); 

    return _instance;

}

- (id)copyWithZone:(NSZone *)zone { 

    return _instance;

}

OC中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?

// 创建线程的方法:

[NSThread detachNewThreadSelector:nil toTarget:nil withObject:nil];

[self performSelectorInBackground:nil withObject:nil];

[[NSThread alloc] initWithTarget:nil selector:nil object:nil];

dispatch_async(dispatch_get_global_queue(0, 0), ^{

});

[[NSOperationQueue new] addOperation:nil];

// 主线程中执行代码的方法:

[self performSelectorOnMainThread:nil withObject:nil waitUntilDone:YES];

dispatch_async(dispatch_get_main_queue(), ^{

});

[[NSOperationQueue mainQueue] addOperation:nil];

什么是 RunLoop

从字面上讲就是运行循环,它内部就是do-while循环,在这个循环内部不断地处理各种任务。

一个线程对应一个RunLoop,基本作用就是保持程序的持续运行,处理app中的各种事件。通过runloop,有事运行,没事就休息,可以节省cpu资源,提高程序性能。

//主线程的run loop默认是启动的。iOS的应用程序里面,程序启动后会有一个如下的main()函数

int main(int argc, char * argv[]) {   

    @autoreleasepool {       

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));   

    }

}

什么是 Runtime?Runtime实现的机制是什么,怎么用,一般用于干嘛?

Runtime又叫运行时,是一套底层的C语言API,其为iOS内部的核心之一,我们平时编写的OC代码,底层都是基于它来实现的。

使用时需要导入的头文件 <objc/message.h> <objc/runtime.h>

Runtime 运行时机制,它是一套C语言库。

实际上我们编写的所有OC代码,最终都是转成了runtime库的东西。比如:

(1).类转成了 Runtime 库里面的结构体等数据类型,

(2).方法转成了 Runtime 库里面的C语言函数,

(3).平时调方法都是转成了 objc_msgSend 函数(所以说OC有个消息发送机制)OC是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector)。 [stu show];  在objc动态编译时,会被转意为:objc_msgSend(stu, @selector(show)); 

因此,可以说 Runtime 是OC的底层实现,是OC的幕后执行者。有了Runtime库,能做什么事情呢? Runtime库里面包含了跟类、成员变量、方法相关的API。 比如:   

(1).获取类里面的所有成员变量。   

(2).为类动态添加成员变量。   

(3).动态改变类的方法实现。   

(4).为类动态添加新的方法等。

因此,有了Runtime,想怎么改就怎么改。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Micheal-董

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值