iOS知识点总结(1)

1. iOS单例的实现方式?

之前总是这样写:

static Singleton *shareSingleton = nil;

  (instancetype)shareSingleton {

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        shareSingleton = [[self alloc] init];

    });

    return shareSingleton;

}

可能创建多次的原因:当使用alloc init创建对象时,在调用alloc方法时,oc内部会调用allocWithZone这个方法来申请内存,为

了避免allocWithZone申请新的内存,可以重写allocWithZone方法,在该方法中调用shareSingleton方法返回单例对象。拷贝对

象也是同样的道理。

可以这样写:

static Singleton *shareSingleton = nil;

  (instancetype)shareSingleton {

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        shareSingleton = [[super allocWithZone:NULL] init];

    });

    return shareSingleton;

}

  (instancetype)allocWithZone:(struct _NSZone *)zone {

    return [Singleton shareSingleton];

}

- (id)copyWithZone:(struct _NSZone *)zone {

    return [Singleton shareSingleton];

}

2. 哪些类不适合使用单例模式?即使他们在周期中只会出现一次?

工具类,不需要存储数据的 例如判断邮箱 电话 字符串是否为纯数字等 可以写成方法

3. timer是否精准, 怎么使用精准的定时器?

正常情况下是精准的,但遇到一下情况就会不准确:

RunLoop的影响:

定时器被添加在主线程中,由于定时器在一个RunLoop中被检测一次,所以如果在这一次的RunLoop中做了耗时的操作,当前

RunLoop持续的时间超过了定时器的间隔时间,那么下一次定时就被延后。

解决办法:

1、在子线程中创建timer,在主线程进行定时任务的操作

2、在子线程中创建timer,在子线程中进行定时任务的操作,需要UI操作时切换回主线程进行操作

RunLoop模式的影响:

为了验证,我们在当前页面上添加一个tableview,在定时器运行时,我们对tableview进行滑动操作,可以发现,定时器并不

会触发下一次的定时任务。

原因分析:

主线程有两种预设模式,分别是RunLoopDefaultModel 和TrackingRunLoopModel 当定时器添加到主线程且没有执行的运行模

式时,一般会 默认添加到RunLoopDefaultModel 一般情况下定时器会正常触发定时任务 但当用户进行滑动操作时,主线程就

会切换成TrackingRunLoopModel 在此模式下定时器不会被触发

解决方法:

添加定时器到主线程的CommonMode中或者子线程中

[[NSRunLoop mainRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];

其他方式的Timer:

使用mach_absolute_time()来实现更高精度的定时器:

iPhone上有这么一个均匀变化的东西来提供给我们作为时间参考,就是CPU的时钟周期数(ticks)。

通过mach_absolute_time()获取CPU已运行的tick数量。将tick数经过转换变成秒或者纳秒,从而实现时间的计算。

GCD定时器:

RunLoop是dispatch_source_t实现的timer,所以理论上来说,GCD定时器的精度比NSTimer只高不低

NSTimeInterval interval = 1.0;

_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));

dispatch_source_set_timer(_timer, dispatch_walltime(NULL,0), interval *NSEC_PER_SEC,0);

dispatch_source_set_event_handler(_timer, ^{

    NSLog(@"GCD timer test");

});

dispatch_resume(_timer);

4. -id、instancetype、NSObject *和id *的区别?

首先需要知道,在cocoa的开发环境里,NSObject是所有类的根类

id:

从定义来看,id就是一个isa指针,可以指向任何一个继承了Object(或者NSObject)类的对象

id可以简单理解为一个万能指针

id是动态数据类型,编译时编译器不会检查id对象的类型,只有在运行时动态检查后会报错。

id 可用于定义变量 定义方法返回值   定义方法参数。

instancetype:

instancetype意思为实例化,instancetype与和id一样,都可以指向一个继承了Object(或者NSObject)类的对象

区别在于:instancetype只能作为方法返回值,需要返回该方法所在的类的实例化对象,所以instancetype也被称为关联返回类型。

使用instancetype会在编译时进行类型检查,有利于开发者在编译阶段发现错误。

关联返回类型的方法:

以 alloc 或 new 开头的类方法

以 autorelease、init、retain 或 self 开头的实例方法。

NSObject*:

NSObject* 就是指向NSObject类型的指针了,可以指向任何一个继承了NSObject的对象,感觉和上面的id、instancetype也没有区别。

区别在于NSObject* 是静态数据类型,编译时会进行类型检查。

NSObject*的作用与id一致。

id *

id *就是指该对象的类型可以是任何一个NSObject或继承了NSObject的子类,但该对象必须要遵循协议(奇葩的命名:协议名与类名一样)。简单来说就是它不关心对象是什么类型,只要遵循协议即可。

在定义delegate时常用。

5. iOS的签名机制?

因为苹果的安全策略,通过签名机制保证手机上的每个App都是经过苹果认证的。

通过App Store安装

开发者可以通过Xcode安装

Ad-Hoc 测试证书打包的App,数量限制100

In-House 企业版证书打包App,信任企业证书后可以使用

由苹果生成一对公私钥,公钥内置与iOS设备中,私钥由苹果保管。

开发者上传App给苹果审核后,苹果用私钥对App数据进行签名,发布至App Store。

iOS设备下载App后,用公钥进行验证,若正确,则证明App是由苹果认证过的。

6. +load和+initilaze在分类,父类,子类和main函数的调用顺序?

+load加载顺序:父类,子类,分类。如果多个分类会按照PBXSourcesBuildPhase中顺序逐个调用。

+initialize加载顺序:首先有分类时,最后被load的分类会覆盖类的该方法。然后先父类,再子类,直到第一次被调用的类。

7.  drawRect方法?

- (void)drawRect:(CGRect)rect;中去绘制一些我们所需要的图形,如虚线、圆形、方形以及曲线等等图形。

1.  我们只能在继承了UIView的子类中通过重写drawRect方法来绘制图形。

2.  如果需要绘制图形的子类直接继承自UIView,则子类的drawRect方法中不需要调用父类方法[super drawRect:rect];。如果子

类继承自其他继承UIView的View类,则drawRect方法中需要调用父类方法[super drawRect:rect];

3.  drawRect方法不能手动直接调用,我们可以通过调用其他方法来实现drawRect方法的调用。如:在子类初始化时调用- (instancetype)initWithFrame:(CGRect)frame方法,且frame不为CGRectZero时。

4.  我们可以调用setNeedsDisplay()方法或setNeedsDisplayInRect方法,但是该方法不会自己调用drawRect方法,而是会标记视图,并在下一次循环更新的时候让视图通过drawRect来进行重绘,前提是rect不为CGRectZero。

8. main()之前的过程有哪些?

Pre-mian 大概过程主要分为:Load dylibs、Rebase、Bind、Objc、Initializers 这几个步骤

1. dyld 开始将程序二进制文件初始化

2. dyld 首先会读取镜像文件,然后递归的查找动态库,利用 ImageLoader 来将其加载到内存中

3. 交由ImageLoader 读取 image,其中包含了我们的类,方法等各种符号

4. 接下来再调用 load_image,遍历调用类的 load 方法、调用C++的构造函数属性函数、创建非基本类型的C++静态全局变量等等。

9. 简述消息转发机制?

从全局来看,消息转发机制共分为3大步骤:

第一步:Method resolution 方法解析处理阶段:

对象在收到无法解读的消息后,首先会调用+(BOOL)resolveInstanceMethod:(SEL)sel或者+ (BOOL)resolveClassMethod:

(SEL)sel, 询问是否有动态添加方法来进行处理,

+(BOOL)resolveInstanceMethod:(SEL)sel(

if(sel==@selector(speak)){

class_addMethod([selfclass],sel,(IMP)speak,"V@:");

returnYES;

}return[

superresolveInstanceMethod:sel];

}

如果在上一步的2个方法内返回的为YES则能接受消息 NO不能接受消息 

第二步: 在-forwardingTargetForSelector:进行判是否转发给有现实这个方法的对象或者类.

-(id)forwardingTargetForSelector:(SEL)aSelector{

Helper*helper=[[Helper alloc]init];

if([helper respondsToSelector:aSelector]){

returnhelper;}

else{returnnil;

}

}

第三步: 实现 -methodSignatureForSelector: 通过正确的类型方法方法签名

-(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector{

return[NSMethodSignature signatureWithObjCTypes:"v@:@"];

}

事不过三,何况操过三次了.处理基本都已经结束了.

实现:-doesNotRecognizeSelector: 在此方法中抛出错误! 然后奔溃

10. objc中向一个nil对象发送消息将会发生什么?

objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类

方法列表中寻找方法运行,然后在发送消息的时候,objc_msgSend方法不会返回值,所谓的返回内容都是具体调用时执行的。 

那么,回到本题,如果向一个nil对象发送消息,首先在寻找对象的isa指针时就是0地址返回了,所以不会出现任何错误。

11. oc的反射机制?

Class对象其实本质上就是一个结构体,这个结构体中的成员变量还是自己,这种设计方式非常像链表的数据结构。

可以直接用一个实例对象或类对象,直接调用Class方法,都可以获取Class对象。

// SEL和字符串转换

FOUNDATION_EXPORT NSString*NSStringFromSelector(SEL aSelector);

FOUNDATION_EXPORT SELNSSelectorFromString(NSString*aSelectorName);

// Class和字符串转换

FOUNDATION_EXPORT NSString*NSStringFromClass(Class aClass);

FOUNDATION_EXPORT Class __nullableNSClassFromString(NSString*aClassName);

// Protocol和字符串转换FOUNDATION_EXPORT NSString*NSStringFromProtocol(Protocol*proto)NS_AVAILABLE(10_5,2_0);

FOUNDATION_EXPORT Protocol*__nullableNSProtocolFromString(NSString*namestr)NS_AVAILABLE(10_5,2_0);

// 当前对象是否这个类或其子类的实例

-(BOOL)isKindOfClass:(Class)aClass;

// 当前对象是否是这个类的实例

-(BOOL)isMemberOfClass:(Class)aClass;

// 当前对象是否遵守这个协议

-(BOOL)conformsToProtocol:(Protocol*)aProtocol;

// 当前对象是否实现这个方法

-(BOOL)respondsToSelector:(SEL)aSelector;

可以解决的实际问题:

假设有一天公司产品要实现一个需求:根据后台推送过来的数据,进行动态页面跳转,跳转到页面后根据返回到数据执行对应的操作。

12. 静态库的原理是什么?你有没有自己写过静态编译库,遇到了哪些问题?

静态库是闭源库,不公开源代码,都是编译后的二进制文件,不暴露具体实现。静态库 一般都是以 .a 或者 .framework 形式存

在。

静态库编译的文件比较大,因为整个函数库的数据都会被整合到代码中,这样的好处就是编译后的程序不需要外部的函数库支

持,不好的一点就是如果改变静态函数库,就需要程序重新编译。多次使用就有多份冗余拷贝。

使用静态库的好处:模块化分工合作、可重用、避免少量改动导致大量的重复编译链接。

framework中用到了NSClassFromString,但是转换出来的class 一直为nil。

解决方法:在主工程的【Other Linker Flags】需要添加参数【-ObjC]即可。

如果Xcode找不到框架的头文件,你可能是忘记将它们声明为public了。

 解决方法:进入target的Build Phases页,展开Copy Headers项,把需要public的头文件从Project或Private部分拖拽到Public部分。

尽量不要用 xib 。由于静态框架采用静态链接,

新建项目,选择Cocoa Touch Static Library   定义一个类方法+ (void)test;,在.h文件暴露出来

然后选择Build phases 清空copy Files 下面的Subpath

适配最低版本 设置支持多个架构的的静态库  Build Active Architecture Only 设置为NO

分别在真机和模拟器下编译 Debug 和 Release

合并.framework 静态库,合成的是二进制文件而不是framework,最后合成的二进制文件替代之前的二进制文件即可

cd 到 Products目录,输入命令(如果是Debug模式,将Release替换成Debug即可)lipo-create Release-iphoneos/MXFrameworkTool.framework/MXFrameworkTool Release-iphonesimulator/MXFrameworkTool.framework/MXFrameworkTool-output MXFrameworkTool

13.ViewController生命周期?

nitWithCoder:(如果连接了串联图storyBoard会走这个方法)或initWithNibName:Bundle:(非storyBoard(Xib或纯代码)都会走这个方法)

init

初始化对象 纯代码和Xib都会走这个方法,storyBoard不会

awakeFromNib

此方法被调用时,所有视图的outlet和action已经连接,但还没有被确定。这个方法可以算作是和视图控制器的实例化配合在一

起使用的,因为有些需要根据用户喜好来进行设置的内容,无法存在storyboard中,所以可以在awakeFromNib方法中被加载进

来。

loadView

对Controller的View进行初始化

viewDidLoad

视图加载完成,但是还没有从屏幕上显示出来,可以重写这个方法,做一些其它的初始化操作,比如移除一些视图,修改约

束,加载数据等操作

viewWillAppear

在视图即将显示到屏幕上的时候调用,可以在这个方法里改变当前屏幕的方向或状态栏风格

iewWillLayoutSubViews

这个方法会在控制器将要布局View的子控件时调用,每当视图的bounds改变时,view将调整其子控件的位置

viewDidLayoutSubviews

此方法会在控制器已经布局子控件的时候调用

viewDidAppear

此方法在视图已经显示在屏幕上的时候调用,可以做一些对视图展示效果的改变

viewWillDisAppear

视图即将消失,被覆盖或被隐藏的时候调用

viewDidDisAppear

视图已经消失,被覆盖或被隐藏的时候调用

didReceiveMemoryWarning

当系统发出内存警告时,会自动清理视图,同时系统会调用此方法来通知视图控制器

可以在此方法内释放一些资源,但通常不需要,因为比较占资源的view已经被清除了

14. 轮播图项目实现细节?

第一种:基于collectionView进行的封装(推荐)

使用UICollectionView的复用特性,复制 多份 图片作为数据源,从中间开始显示

在 第一张图片前加 上最后一张图片,在最后一张图片前加上第一张图片

注意:

记得设置scrollView.isPagingEnabled = true

控制UIScrollView回滚的时候 不要使用动画,否则会调用代理方法

第二种:基于scrollView的无限轮播(首尾各多创建一个展示图片的ImageView)

第三种:同样是基于scrollView的无限轮播(总共就创建三个ImageView)

15. 单行多个Label,中间可压缩,怎么添加约束?

[self.label1 setContentHuggingPriority:1forAxis:UILayoutConstraintAxisHorizontal];

[self.label1 setContentCompressionResistancePriority:2forAxis:UILayoutConstraintAxisHorizontal];

你可能感兴趣的:(iOS知识点总结(1))