60面试问题每个iOS开发人员都应该知道。 (第1部分)


在这第一篇博客文章中,我试图介绍有关ObjectiveC的简单问题。 所有问题的答案均​​来自多个来源。 如果您对以下任何问题有更好的答案,请将其作为评论发送。 (此博客的版权归所有在多个博客,QnA网站和Apple Developer文档中提到这些答案的开发人员所有)

1.解释什么是Objective-C协议。

协议声明了任何类都可以选择实现的程序接口。 协议使通过继承关系远的两个类彼此通信以实现某个目标成为可能。

在这里阅读更多。

2.解释协议的类型。

正式协议声明了客户端类应实现的方法列表。 正式协议具有自己的声明,采用和类型检查语法。 您可以使用@required和@optional关键字来指定其实现是必需的还是可选的方法。 子类继承其祖先采用的正式协议。 正式协议也可以采用其他协议。 正式协议是对Objective-C语言的扩展。

非正式协议是NSObject上的一个类别,它隐式地使几乎所有对象都采用该协议。 (类别是一种语言功能,使您可以将方法添加到类中而不对其进行子类化。)在非正式协议中实现方法是可选的。 在调用方法之前,调用对象将检查目标对象是否实现了该方法。 在Objective-C 2.0中引入可选协议方法之前,非正式协议对于Foundation和AppKit类实现委派的方式至关重要。

3.解释什么是#import。

#import确保文件只包含一次,因此您不会遇到递归包含的问题。

4. Objective-C中的#import和#include有什么区别?

导入是包含的超级集,它确保文件仅包含一次。 这样可以避免递归包含。 关于“”和。 在本地目录中搜索“”,<<用于系统文件。

5,Objective-C中类别的用途是什么?

通常,您可以使用类别将方法添加到现有类中,例如Cocoa框架中定义的方法。 所添加的方法由子类继承,并且在运行时与类的原始方法没有区别。 您还可以使用自己的类的类别来:将自己的类的实现分发到单独的源文件中-例如,您可以将一个大类的方法分组为几个类别,然后将每个类别放入一个不同的文件中。 声明私有方法。

#import“ SystemClass.h”

@interface SystemClass(类别名称)

//方法声明

@结束

6.类别的局限性和问题?

优点:您可以扩展没有源的任何类,甚至那些类。 例如,查看Apple添加到NSString类的UI扩展,以进行渲染,获取指标等。由于您可以访问所有实例变量,因此类别为您提供了一种使用逻辑在跨编译单元的结构化代码的好方法分组,而不是例如Java采取的“必须全部在一个物理位置”进行分组。 缺点:您不能安全地覆盖该类本身或另一个类别已经定义的方法。

7.说明何时使用NSArray和NSMutableArray。 哪一个更快且线程安全?

NSArray及其子类NSMutableArray管理称为数组的对象的有序集合。 NSArray创建静态数组,NSMutableArray创建动态数组

在这里阅读更多。

8.什么是快速枚举?

该对象通常是诸如数组或集合之类的集合。若干个Cocoa类(包括集合类)采用NSFastEnumeration协议。 您可以使用它来检索实例持有的元素,其语法类似于标准C for循环的语法,如以下示例所示:

NSArray * anArray = //获取一个数组;

for(anArray中的id元素)

{

/ *作用于元素的代码* /

}

在这里阅读更多。

9,解释什么是Objective-C中的@synthesize

@synthesize为变量创建一个getter和setter。 这样,您可以为变量指定一些属性,并在将该属性@synthesize到变量时,将为该变量生成getter和setter。

10.解释如何在Objective-C中调用函数。

调用方法是这样的

[className methodName]

但是,如果要在同一类中调用该方法,则可以使用self

[自身methodName]

11.解释什么是点符号

点语法只是调用getter和setter的快捷方式,即:

[foo长度]

foo.length

完全相同,如下所示:

[foo setLength:5]

foo.length = 5

12.提及NSObject是父类还是派生类。

Objective-C定义了一个继承自绝大多数其他类的根类,称为NSObject。 当一个对象遇到另一个对象时,它期望至少能够使用由NSObject类描述定义的基本行为进行交互。

在这里阅读更多。

13.解释原子和非原子合成特性之间的区别。

原子行为是默认行为,它将确保当前进程已由CPU完成,而另一个进程访问该变量之前速度并不快,因为它可以确保该进程完全完成

非原子性不是默认行为的更快(对于合成代码,即对于使用@property和@synthesize创建的变量),当两个不同的进程同时访问同一变量时,非线程安全的行为可能导致意外行为。

14.什么是GCD? 与NSThread相比有什么优势?

GrandcentralDispatch :因为您的设备只有一个处理器,所以GCD可能只创建一个线程来执行块,并且您的块按顺序执行。 但是,您已经创建了10个不同的线程,并且每个线程都只占可用处理时间的一小部分。 幸运的是,睡眠不是很消耗处理器,因此所有线程都可以很好地运行。 在具有4个或8个处理核心的机器上尝试类似的测试,您会看到GCD并行运行更多的块。

GCD的好处不是不一定提供比线程更好的性能,而是程序员不必考虑创建线程或将线程数量与可用处理器数量相匹配。 您可以创建许多小任务,这些任务将在处理器可用时执行,并让系统为您安排这些任务。

15.什么是KVC和KVO? 举一个使用KVC设置值的示例。

键值编码(KVC)表示使用字符串访问属性或值。 id someValue = [myObject valueForKeyPath:@” foo.bar.baz”];

可能与以下内容相同:

id someValue = [[[[myObject foo] bar] baz];

键值观察(KVO)允许您观察对属性或值的更改。

要使用KVO观察属性,您将使用字符串将属性标识为; 即使用KVC。 因此,可观察对象必须符合KVC。

[myObject addObserver:self forKeyPath:@” foo.bar.baz”选项:0上下文:NULL];

16.什么是方块?如何使用?

块是C,Objective-C和C ++中添加的一种语言级别的功能,可让您创建不同的代码段,这些代码段可以作为值传递给方法或函数。

定义块文字的语法使用插入符号(^),如下所示:

^ {

NSLog(@“这是一个块”);

}

17.什么是响应链?

响应者链是一系列链接的响应者对象。 它以第一个响应者开始,以app对象结束。 如果第一个响应者无法处理事件,则将事件转发给响应者链中的下一个响应者。

18. ID是什么?

id是指向任何类型的指针,但与void *不同,它始终指向Objective-C对象。 例如,您可以将任何类型为id的东西添加到NSArray中,但是这些对象必须响应以保持和释放。

19.什么是instanceType?

@interface A:

NSObject —(实例类型)init;

@结束

@接口B:A

@结束

A的init方法继承到B。但是,在两个类中,该方法都有不同的返回类型。 在A中,返回类型为A,在B中,返回类型为B。

没有其他方法可以正确声明初始化程序的返回类型。 请注意,大多数带有类的编程语言甚至都没有构造函数的返回类型,因此它们完全避免了该问题。

这就是为什么Obj-C需要实例类型,但是当然也可以在初始化程序之外使用它的原因。

20. id和instanceType是否相同? 如果没有,它们之间有什么区别?

在您的代码中,在适当的地方用instancetype替换id的出现作为返回值。 初始化方法和类工厂方法通常是这种情况。 即使编译器自动转换以“ alloc”,“ init”或“ new”开头且具有ID返回类型ID的方法以返回instancetype,它也不会转换其他方法。 Objective-C约定是为所有方法显式编写实例类型。

21. Objective-C是否具有函数重载?

Objective-C不支持方法重载,因此您必须使用不同的方法名称。

22.什么是代表? 可以保留代表吗?

委托是一个在另一个对象遇到程序中的事件时代表另一个对象或与另一个对象协同工作的对象。

由你决定。 如果您声明要保留它(在ARC中为强),它将被保留。

规则是不要保留它,因为它已经在其他地方保留了,更重要的是您将避免保留周期。

23.什么是课程扩展? 我们为什么需要它们?

使用Objective-C,您可以通过类别和类扩展将自己的方法添加到现有类中。

类扩展扩展了内部实现。

类扩展与类别具有某些相似性,但是只能将其添加到您在编译时拥有源代码的类中(该类与该类扩展同时进行编译)。 由类扩展声明的方法是在原始类的@implementation块中实现的,因此,例如,您不能在框架类(如NSString这样的Cocoa或Cocoa Touch类)上声明类扩展。

声明类扩展的语法类似于类别的语法,如下所示:

@interface ClassName()

@结束

因为括号中没有给出名称,所以类扩展通常称为匿名类别。 与常规类别不同,类扩展可以将自己的属性和实例变量添加到类中。

在这里阅读更多。

24.谁调用dealloc方法? 我们可以在ARC中实现dealloc吗? 如果是,那需要做什么?

由于内存管理而调用dealloc。 一旦对象“ retainCount”达到0,则将自动向该对象发送取消分配消息。

除非它是对[super dealloc]的调用,否则切勿在对象上调用dealloc。 在重写的dealloc的末尾。

(无效)

{

[ivar版本]; //在超级释放之前释放所有保留的变量

[super dealloc]; //只有在代码中放置您才应该调用dealloc

}

25.您可以为保留属性编写setter方法吗?

是的,要提供自定义访问逻辑,您将需要编写自己的getter和setter方法。

26. dispatch_once如何管理仅运行一次?

dispatch_once()是同步过程,所有GCD方法都是异步进行的(例如,dispatch_sync()是同步的)

dispatch_once()的整个想法是“一次执行一次,只有一次”,这正是我们正在做的事情。 dispatch_once用于保证某件事仅发生一次,无论程序的线程变得多么暴力。

27.什么是NSAutoreleasePool? 什么时候使用它们?

NSAutoreleasePool类用于支持Cocoa的引用计数的内存管理系统。 自动释放池存储当池自身耗尽时向其发送释放消息的对象。

另外,如果您使用自动引用计数(ARC),则不能直接使用自动释放池。 而是使用@autoreleasepool块。 例如,代替:

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

//受益于本地自动释放池的代码。

[池释放];

你会这样写:

@autoreleasepool

{

//受益于本地自动释放池的代码。

}

@autoreleasepool块比直接使用NSAutoreleasePool实例更有效; 即使不使用ARC,也可以使用它们。

28.使用performSelectorInBackground:withObject:创建的线程是否创建自己的自动释放池?

performSelectorInBackground:withObject:方法将创建一个新的分离线程,并将指定的方法用作新线程的入口点。 例如,如果您有某个对象(由变量myObj表示),并且该对象具有要在后台线程中运行的名为doS​​omething的方法,则可以使用以下代码来执行此操作:

[myObj performSelectorInBackground:@selector(doSomething)withObject:nil];

调用此方法的效果与使用当前对象,选择器和参数对象作为参数调用NSThread的detachNewThreadSelector:toTarget:withObject:方法的效果相同。 立即使用默认配置生成新线程并开始运行。 在选择器内部,必须像配置任何线程一样配置线程。 例如,如果您打算使用自动释放池(如果您不使用垃圾回收),则需要设置它,并配置线程的运行循环。 有关如何配置新线程的信息,请参阅“配置线程属性”。

在接受面试之前,您必须阅读此书。

29.目标C是一种动态语言吗? 对/错,解释。

的确,Objective-C(不要忘记连字符)是C和Smalltalk之间的交叉。 前者是一种静态类型的语言。 后者是动态键入的。 因此,Objective-C不仅是一种动态语言。

30.当我们在nil指针上调用方法时会发生什么?

发送到nil对象的消息在Objective-C中是完全可以接受的,它被视为无操作。 没有办法将其标记为错误,因为它不是错误,实际上,它可能是该语言的一个非常有用的功能。 它返回0,nil,填充为0的结构等。

31.什么时候可以使用CFArray / Dictionary代替NSArray / Dictionary?

核心基金会是行动的大脑。 它主要是用C编写的。它是由Apple收购NEXT及其API创建的,这归功于他们。 NS *类通常只是建立在CF *类型之上的Objective C抽象接口。 因此,当您问为什么CFArray和NSArray同时存在时,答案是它们实际上不存在。 NSArrays是CFArrays,NSStrings是CFStrings,等等。这就是免费电话桥接成为可能的原因。

32.什么是免费桥接,什么时候有用?

免费电话桥接意味着数据结构是可互换的。 就像铸造一样简单-这是“免费”的部分。 在任何地方都可以在桥的一侧使用该类型,也可以在另一侧使用。 因此,例如,您可以创建一个CFString然后向其发送NSString消息,或者可以创建一个NSArray并将该数组传递给CFArray函数。

33. @synchronized()有什么作用?

@synchronized指令是在Objective-C代码中动态创建互斥锁的便捷方法。 @synchronized指令执行任何其他互斥锁将执行的操作-防止不同的线程同时获取同一锁。

34.下划线和self(即self.xx和_xx)有什么区别?

当您使用self.XX时,可以通过setter或getter访问该属性。

当使用_XX时,您直接访问属性直接跳过setter或getter

35.什么是扩展名?

扩展名实际上是没有类别名称的类别。 通常称为匿名类别。 声明扩展的语法使用@interface关键字,就像标准的Objective-C类描述一样,但不表示从子类继承任何继承。 相反,它仅添加括号,如下所示

@interface ClassName()

@结束

36.什么是进程,线程?

进程和线程都是独立的执行序列。 典型的区别是(同一进程的)线程在共享内存空间中运行,而进程在单独的内存空间中运行。

37.反思? 类自省? objc和可可中有什么吗?

类自省:这是在运行时提供有关对象/类的信息的能力。 Objective C运行时支持自省。 objC运行时提供的信息类型的小样本

  1. 类对象中类的方法名称。

2)有关方法参数的信息

3)一类的单个方法的实现(IMP)

4)有关类的实例变量的信息

反射:它具有添加新类和添加/修改现有类的接口的能力。 它还具有修改类之间关系的功能,例如,objC运行时允许添加新的类,方法可以添加到类中,实例变量可以添加到在运行时创建的类中。 它还允许将一个类的超类替换为另一个类。

Swizzling:目标C中的“ Swizzling”一词是指在运行时交换两种方法(类或实例)的实现。 因此,您可以将自省应用于访问方法的实现和反射,以实际交换方法的实现以实现混乱。

在这里阅读更多。

38.如何使代码段线程安全?

线程安全代码是由多个线程执行时仍然正确的代码。 因此,任何操作顺序都不会违反规范。

1多线程执行期间将保持不变式和条件,而无需客户端进行额外的同步

2.重点是:线程安全要求规范在多线程执行期间成立。 要实际编写此代码,我们只需要做一件事:限制对可变共享状态的访问

3.共有三种方法:阻止访问。 使状态不变。 同步访问。

前两个很简单。 第三个要求防止出现以下线程安全问题:

活动死锁:两个线程永久阻塞,彼此等待释放所需的资源。

livelock:线程正在忙于工作,但无法取得任何进展。

饥饿:一个线程被永久拒绝访问其取得进展所需的资源。

安全发布:已发布对象的引用和状态必须同时对其他线程可见。

竞态条件:竞态条件是一种缺陷,其中输出取决于不可控制事件的时间。 换句话说,当获得正确答案取决于幸运时机时,就会发生竞争状况。 任何复合操作都可能会遇到竞争状况,例如:“先检查后行动”,“如果没有则投入”。 一个示例问题是if(counter)counter —;,几种解决方案之一是

@synchronize(个体)

{

if(counter)计数器-;

}。

39.创建块时会发生什么?

块还用于回调,定义任务完成时要执行的代码。 例如,您的应用可能需要通过创建执行复杂任务的对象来响应用户操作,例如,从Web服务请求信息。 由于任务可能需要很长时间,因此您应该在任务执行时显示某种进度指示器,然后在任务完成后隐藏该指示器。

40.什么是isa成员?

Objective-C对象基本上是C结构。 每个对象都包含一个称为isa的字段,该字段指向该对象是其实例的类的指针(这就是该对象和Objective-C运行时如何知道其是哪种对象的方式)。

41.如果将刚创建的对象添加到可变数组,然后释放对象,会发生什么情况?

这取决于。 如果在将对象添加到数组之前拥有该对象,则仍必须释放自己的所有权声明以避免泄漏—该数组对对象的所有权声明是单独的,并且不承担任何关于内存的责任。管理规则。

对象* obj = [[Object alloc] init];

[anArray addObject:obj];

[obj版本];

另一方面,如果您不拥有该对象,那么在将其添加到数组之后,您仍然不拥有它,并且仍然不能释放它。 数组确实会建立自己的所有权声明,但是就像您自己的代码一样,它负责平衡自己的声明。

对象* obj = [对象对象];

[anArray addObject:obj];

//或避免使用temp变量

[anArray addObject:[Object object]];

42.如果释放数组,对象将如何处理?

释放数组与从数组中删除所有项目具有相同的效果。 也就是说,阵列不再要求它们的所有权。 如果其他人保留了这些对象,它们将继续存在。 如果没有,它们将被释放。

43.我们不能放入数组或字典中的内容是什么?

nil不是可以添加到数组的对象:数组不能包含nil。 这就是为什么addObject:nil崩溃的原因。

44.如何将nil放入字典/数组中?

由于C var args的工作原理,initWithObjects:中的nil仅用于告诉方法列表在何处结束。 使用addObject逐个添加对象时:不需要添加nil。

45.目标C的构成是什么?

摆姿势 Objective-C允许一个类完全替换应用程序中的另一个类。 替换类被称为“摆在”目标类。 然后,所有发送给目标类的消息都由冒充类接收。

46.我们可以在目标C中创建动态类吗? 如果是,请说明如何使用有效的用例进行创建?

要使用其名称实例化一个类,可以使用

NSClassFromString:id obj = [[NSClassFromString(@“ MySpecialClass”)alloc] init];

47.如果将任何消息发送到已释放的对象会发生什么?

在对象上调用release不一定意味着它将被释放。 它只是减少对象的保留计数。 直到保留计数达到0为止,对象才被释放(即使那样,对象可能在自动释放池中,但那时还没有被释放)。

因此,您可以释放对象,但仍可以指向它。 然后它可以自动发布。 然后,您向它发送一条消息-但现在该对象可能是垃圾。

48. iOS设备支持哪些CPU体系结构?

iPhone 5、5c,5S,iPod touch-5,iPad-4,iPad Air支持Armv7s。 只是基于处理器而已。 为A6处理器设计的Armv7。 从IOS6 +支持。 它还支持64位编码,但是在具有armv7s指令集的设备中处理速度变慢。

与Arm64设备相同,它们来自Iphone 5s,iPad Air。 这与A7处理器有关。 这些设备的最大优势是对64位的支持。

49.我可以在同一.m文件中编写一些C ++函数吗? 会编译吗? 如果没有,我应该怎么做才能编译它?

最简单的解决方案是简单地告诉Xcode将所有内容编译为Objective C ++。

设置项目或目标设置以将源代码编译为Objective C ++并重新编译。

然后,您可以在任何地方使用C ++或ObjectiveC。

50.您可以使用XCode创建哪些iOS二进制文件? (.app,.ipa,.a,.framework)

您可以创建.app,.ipa,.a和.framework

51.静态库(.a)是否可以包含图像,声音文件等资源?

不,除了静态库的代码外,您不能提供其他任何东西。 这是因为.a文件是目标文件的简单存档,并且在Mac / iOS下具有支持多种CPU架构的附加功能。

您唯一的选择是创建一个框架,该框架可以提供代码以及其他资源。

52.什么是捆绑包?

捆绑包只是一个自包含的可执行文件。 运行它时,它将执行内部定义的主要功能,并且仅使用其包含的资源。

53.说明应用程序生命周期或应用程序状态。

这些状态称为应用程序生命周期的状态。 当应用在其生命周期的状态中移动时,其状态由其活动级别(例如未运行,活动或已暂停)定义。

以下是有关状态的更多信息:

-当应用程序处于“未运行”状态时,该应用程序尚未启动或系统将其关闭。

-当应用启动时,它会过渡到一个简短的状态,称为非活动状态。 它实际上正在运行,但是正在执行其他功能,尚不能接受用户输入或事件。

-处于活动状态的应用在前台运行并接收事件。 这是前台应用程序的正常模式,这些应用程序无需用户界面即可在后台运行。

-当应用程序处于“后台”状态时,其用户界面不可见,但正在运行。 大多数应用会在暂停状态下通过此状态转换。

-应用可能需要(并请求)额外的执行时间,并且可能会在此状态下停留一段时间。 另外,某些应用程序在后台运行。 这样的应用会直接进入“背景”状态,而不会进入“非活动”状态。

-iOS系统可能会将应用程序移至“暂停”状态。 该应用程序在后台运行,但未运行代码。 但是,它确实保留在内存中。 如果发生内存不足的情况,系统可能会在未通知的情况下清除处于挂起状态的应用程序。 请注意,根据Apple的标准,只有iOS系统可以终止应用程序。

54.为什么要创建自定义视图?

您还可以创建一个自定义视图来封装您自己的可重用组件的视觉外观和行为。 例如,在新闻阅读应用程序中,我们可能希望标准组件在主页视图控制器和单个故事视图控制器上使用一致的样式显示带有标题的图像。

55.什么是尺码等级?

大小类是分配给用户界面元素(例如场景或视图)的特征。 它们提供了元素大小的粗略指示。

56.如何在视图中布局子视图?

addSubview导致在要添加的视图,要添加到的视图(目标视图)以及目标的所有子视图上调用layoutSubviews。

57. UIWindow和UIView之间的区别。

Windows本身没有任何可见的内容,但为应用程序的视图提供了基本的容器。 视图定义要填充某些内容的窗口的一部分。 通常,iOS应用程序中只有一个窗口。

58. iOS中可以有多个UIWindows吗?

是的,应用程序可能有一个附加窗口,用于在外部显示器上显示内容。

59.收款视图的好处是什么?

  • 允许定制的布局可能非常复杂(例如:每个单元的大小不同)
  • 一排支持多个单元
  • 提供水平滚动方向,无需创建滚动视图即可达到相同的效果
  • 支持基于布局的单元格自定义动画
  • 可以实现拖放功能
  • 页眉和页脚设置的更多选项,不需要固定在顶部或底部
  • 不包含空白单元格

60. Xib / storyboard与笔尖的区别?

有些故事板可以做的事情,笔尖无法做到。 情节提要可让您在视图控制器之间创建脚本,还可以就地设计表格视图单元。

笔尖可以做的事,情节提要不能做。 在笔尖中,可以创建对文件所有者占位符的引用。 您可以创建,编辑多个顶级视图,以及在它们之间创建连接。 请参阅此答案以获取有关为什么要这样做的示例。 您可以添加外部对象占位符(一种很少使用的功能)。

在此处检查第2部分。