凡经历过iOS面试的我们总会发觉,即使实际开发中做过许多项目,也难免为一个普通的面试题受挫。这也许不是因为我们技术不过关,而是因为在平时我们忽略了怎样将用到的知识很好的表述出来。闲暇之余我把一些常见的iOS面试问题总结一下,即使不是为了面试,也有助于对基础知识的回顾。 此篇总结在iOS日常开发中经常遇到的基本概念性问题:
1.原子性:nonatomic 、atomic 2.读写: readwrite 、readonly 3.方法名:getter=<name>、setter=<name> 4.内存:strong、retain、copy、weak、assign 、unsafe_unretained
atomic:原子性,只有一个线程可以同时访问实例。atomic 是线程安全的,至少在当前的读取器是安全的。虽然它是一个默认属性,但是由于其使用同步锁开销较大,会损耗性能。 nonatomic:非原子性的,可以被多个线程访问。效率要比atomic 高,但是不能保证其在多线程状态下的安全性,在单线程和明确只有一个线程访问的情况下被广泛使用。
readwrite(默认值):表示其同时拥有getter 和 setter 方法; readonly:只读操作,其只有getter 方法,没有setter法 注:如果某个实例只允许被外部读取,而不能写入操作,同时在类实现文件当中可以写入的话,可以在头文件中声明属性为只读的,在实现文件中设置其为可读写的属性,写法如下:
//头文件中声明为:
@property(nonatomic,readonly,copy) NSString *stringA;
//实现文件中声明为:
@property(nonatomic,readwrite,copy) NSString *stringA;
getter=<name>的样式: @property (nonatomic, getter=isOn) BOOL on;
assign:用于值类型(如int,float等) weak: 用于修饰引用类型 unsafe_unretained:只修饰引用类型 区别:
strong:用于引用类型,强引用。 retain :用于引用类型,强引用。 copy:修饰属性会在内存里拷贝对象。 区别:
iOS应用沙盒即文件系统目录,与其他应用的文件系统隔离
栈区(stack):由系统自动分配和释放,存放局部变量的值,容量小速度快,有序 堆:一般由程序员分配和释放,如果不释放,则出现内存泄露。程序会回收您的内存,特点:容量大,速度慢,无序 静态存储区:全局变量(外部变量)和静态变量都存放在静态区域。当程序结束使,系统回收 常量区:存放常量的内存区域,程序结束时,系统回收 代码区:存放二进制代码的区域
简易推送流程:
(1) 应用程序安装后提示用户是否需要接收推送,用户确认后注册消息推送。 (2)App接收到从APNS Server获取的令牌信息; (3)APP将令牌信息发送到自己的服务器端; (4)当需要向用户推送消息时,自己的服务器将向苹果的推送通知服务器(Apple Push Notification Service,以下简称 APNS)发送通知; (5)APNS 会向装有此APP的iPhone设备发送消息
第三方推送的原理(以个推为例):
//如果需要在block中对num进行修改,需要加上关键字__block
//(我们也可以用static关键字进行修饰)
int num1 = 10;
void(^block1)() = ^{
NSLog(@"num1 is %d",num1);
};
num1 = 20;
block1(); //输出10
//改进:使用block,使进入到block块中的变量不被当做常量来使用
__blockint num2 = 10;
void(^block2)() = ^{
NSLog(@"num2 is %d",num2);
};
num2 = 20;
block2(); //输出20
循环引用举例:
NSMutableArray *firstArray = [NSMutableArray array];
NSMutableArray *secondArray = [NSMutableArray array];
[firstArray addObject:secondArray];
[secondArray addObject:firstArray];
检测循环引用 Xcode -> Product -> Pofile -> Leaks
用变量a给出下面的定义原文链接 a) 一个整型数 b) 一个指向整型数的指针 c) 一个指向指针的的指针,它指向的指针是指向一个整型数 d) 一个有10个整型数的数组 e) 一个有10个指针的数组,该指针是指向一个整型数的 f) 一个指向有10个整型数数组的指针 g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数 h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数
a) int a; // An integer
b) int *a; // A pointer to an integer
c) int **a; // A pointer to a pointer to an integer
d) int a[10]; // An array of 10 integers
e) int *a[10]; // An array of 10 pointers to integers
f) int (*a)[10]; // A pointer to an array of 10 integers
g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer
1.概念理解: 多线程是针对于单核的CPU来设计的,目的是为了让CPU快速在多个线程之间进行调度。 多线程的优缺点 优点:提高程序的执行效率 缺点:开启线程需要一定的内存空间
同步和异步:决定了可不可以开启新的线程 同步:在当前线程中执行任务,不具备开启新线程的能力 异步:在新的线程中执行任务,具备开启新线程的能力
并行与串行:决定了任务的执行方式 并行:多个任务并发(同时)执行。类型迅雷,多个任务同时开启下载 串行:一个任务执行完毕后,再执行下一个任务。类似浏览器的一个接一个下载
iOS应用程序中都是一个主线程,也成为UI线程 那么主线程的作用就是用来更新UI,显示或者刷新界面 注意:不能将耗时的任务放在主线程上,否则会出现卡顿的现象。
2.iOS的三种多线程编程技术 NSThread 直接操作线程对象,但需要手动管理生命周期,而且经常使用这种方式来查看当前线程 GCD(Grand Central Dispatch) 底层使用的是C语言,灵活方便,可以根据系统负荷来增减线程,性能效率更好 Cocoa NSOperation NSOperation对GCD的封装,使用起来更好理解,将任务封装为NSOpertaion,添加到NSOPerationQueue对象中 子类化NSOpertaion的设计,更具有面向对象(封装,复用)的特性。更加适合在复杂项目中使用
3.进程与线程 Progress和Thread,进程和线程是操作系统里的基本概念 线程与进程的区别: 线程是资源分配的最小单位,也是处理器调度的基本单位,但是进程不是 进程是资源拥有的单位,同一个进程内的线程共享进程里的资源 多进程,允许多个任务同时运行 多线程,允许单个任务分为不同的部分运行
音频的播放从形式上分为音频播放和音乐播放。 音频播放:通常时间较短,不需要进度控制,和循环控制。使用AudioToolbox.framework。 音乐播放:通常时间较长,需要进行精准控制。使用AVFoundation.framework。
音频播放 AudioToolbox.framework是基于C语言的框架。 原理:将短音频注册的到系统声音服务(System Sound Service)中。System Sound Service是一种简单、底层的声音播放服务。 1.音频播放时间不能超过30秒。 2.数据必须是PCM或者IMA4格式。 3.音频格式必须打包成.caf、.aif、wav中的一种。(这是官方说法,实际发现一些.mp3也可以)。
音乐播放 1.适合播放较大的音频。 2.可以对音频进行精准的播放控制 3.使用AVFoundataion.framework中的AVAudioPlayer来实现。 使用: 1.初始化AVAudioPlayer对象,通常是指定本地文件路径 2.设置播放器属性,例如重复次数,音量大小等。 3.调用play方法播放。
注意:AVAudioPlayer一次只能播放一个音频文件,所有的上一曲和下一曲都是通过创建多个AVAudioPlayer来实现的。
Apple已经为我们提供了多种方法来实现视频播放,包括MPMoviePlayerController,MPMoviePlayerViewController,AVPlayer,AVPlayerViewController等。而值得注意的是,上述的MPMoviePlayerController与MPMoviePlayerViewController在iOS9.0之后被弃用。下面是四种播放方式的区别:
Class class = NSClassFromString(@“Student”);
Student *student = [[class alloc] init];
Class class = [student class];
NSString *calssName = NSStringFromClass(class);
SEL selector = =NSSelectorFromClass(@“setName”);
[stu performSelector:selector withObject:nil];
NSStringFromSelector(@selector *( “setName:”));
开辟内存空间 初始化参数 返回内存地址值
1、 初始化方法事不会调用 2、滚动UIScrollview触发 3、旋转屏幕时触发 4、改变View的值时候触发,前提是frame改变了 5、改变UIView的大小时触发
NSOperationQueue是存放NSOPeration的集合类,可以参考JAVA中的线程和线程池的概念。 虽说是queue,但并不是队列的意思,并不遵守先进先出。 所以我们可以理解为Pool ,即线程池。
OC将数据、对象类型的确定从编译阶段推迟到了运行时。实现这一操作的基础是面向对象语言的多态特性。 这里面有有两个关键字:运行时和多态 运行时:运行时机制使我们知道运行的时候才确定一个对象的类型、以及调用该类别对象指定的方法。 多态:不同的对象以自己的方式来响应相同的消息。子类的指针可以赋值给父类。
“queue中所执行的代码不一定在main thread中。如果queue是在主线程中创建的,那么所执行的代码就是在主线程中执行。如果是在子线程中创建的,那么就不会在main thread中执行。“ 上述说法并不完全正确,queue中所执行的代码不一定在主线程是对的,但是队列Queue中执行的任务是在否在主线程与创建队列所在的线程并无关系。
对于这个问题,首先总结几个知识点: 1.iOS中获取队列的三种方式: 主线程队列: 主线程队列为串行队列,和主线程绑定。同普通串行队列一样,队列中任务一次只能执行一个,但是队列中所有任务都在主线程中执行(经过测试,即使是异步添加的任务,也没有创建新的线程)。
全局队列: 系统全局队列为并发队列,根据不同的优先级(HIGH、DEFAULT、LOW、BACKGROUND)有四个。
自定义队列: 系统提供方法,可以自定义创建串行和并行队列。
2.同步与异步,串行与并行 同步与异步:决定可不可以开启新的线程 同步:在当前线程立即执行添加的任务,不具备开启新线程的能力。 异步:在新的线程中执行任务,具备开启新线程的能力
并行与串行:决定了任务的执行方式 并行:可以多个任务并发(同时)执行。类型迅雷,多个任务同时开启下载 串行:一个任务执行完毕后,再执行下一个任务。类似浏览器的一个接一个下载
对于这个问题,我使用代码测试了使用的情况如下:
总结:队列Queue中执行的任务是在否在主线程与创建队列所在的线程无关。
判断一个任务是不是在主线程,我们可以首先判断同步还是异步,因为异步才具有开启新线程的能力。然而我们还需要注意两点: 1.主线程所在队列为串行队列,添加同步会导致死锁。 2.并非所有的异步任务都不在主线程中,主线程队列中添加异步任务,并不开启新的线程。
302是请求重定向。 500及以上是服务器错误,如503表示服务器找不到、3840表示服务器返回无效JSON。 400及以上是请求链接错误或者找不到服务器,如常见的404。 200及以上是正确,如常见的是200表示请求正常。 更多参考: Http状态码详细说明
对于细碎知识点的学习,经过了不断的测试和理解,我们才会发现还有太多值得研究的地方。非常感谢评论区不少朋友帮我提出的问题,如果有不对的地方我也会尽快更正。