美文网首页
iOS常用面试题一

iOS常用面试题一

作者: 白菜的大猪猪 | 来源:发表于2019-04-15 16:15 被阅读0次

    200道常用的iOS题目

    1、swift和oc的区别    没啥意义的题

    2、编译链接

    a) 编译

    什么叫编译?    

            将C源程序翻译成计算能识别的0和1

    使用什么编译器:

            Xcode3是用GCC,XCode4使用LLVM编译器(前端clang)

    如果使用clang编译程序?

            在终端中输入:CC -c 文件名.c。(cd进入当前目录下)

            编译成功,会生成.o目标文件。

    编译的过程

            a.预处理

            b.检查语法

            c.编译.

    b) 连接

    连接的作用:

            将.o文件和C语言函数库组合在一起,生成可执行文

    由连接器完成,clang编译器里面已经包含了连接指令。

            终端输入:cc 文件.o。

            连接成功,会生成a.out可执行文件。


    3、synthesize & dynamic

    @property= ivar(实例变量) +getter/setter(存取方法);

    @property有两个对应的词,一个是 @synthesize,一个是 @dynamic。如果 @synthesize和 @dynamic都没写,那么默认的就是@syntheszie var = _var;

    @synthesize  

            a)、自动生成成员变量的同时还生成了set和get方法  

            b)、如果不想编译器自作主张生成这些setter和getter方法,则使用@dynamic。  

                    @dynamic (Xcode6以后省略这个了, 默认在 @implementation .m中添加这个@dynamic xxx; ),告诉编译器,不自动        生成getter/setter方法,避免编译期间产生警告,然后由自己实现存取方法或存取方法在运行时动态创建绑定:主要使用在CoreData的实现NSManagedObject子类时使用,由Core Data框架在程序运行的时动态生成子类属性。

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

    4、在项目开发中常用的开发工具有哪些?

    Xcode 、Postman(网络请求发送) 、 SQLPro Studio(数据库)、sourcetree(远程库)、青花瓷(Charles)、easyAPNs(消息推送)、glogg(大日志文件查看)、transmit(sftp工具)、teamViewer(远程控制电脑)、instruments(Xcode自带的  性能方面检测工具)

    5、UITableView & UICollection

        两者的区别

            UICollectionView默认没有表头,  UITableView: 有表头和表尾;

            UICollectionView的区里面是项Item, UITableView:区里面是单元格Cell

            UICollectionView布局使用UICollectionViewLayOut的子类(UICollectionViewFlowLayOut 流式布局:流式布局的特点就是会自动根据屏幕的宽度适当的显示列数,如果屏幕款显示的列数可能就多,例如iphone 6s Plus, 如果屏幕相对较窄,显示的列数则较少,例如 iphone 4s)

            UICollectionView和UITableView都是分区(段)的

            两者都使用了子view的重用机制

            最大区别  一个适合做 流式布局   一个适合做线性布局

        uitableview 的优化

                1、 避免主线程阻塞

                2、对象的创建会发送内存分配、属性调整等。

                        所以,首先,尽量用轻量的对象代替重量的对象。比如CALayer代替UIView。

                        接着,多利用缓存思想,对象创建后缓存起来,需要的时候再拿出来用。合理利用内存开销,减少CPU开销。

                        关于这一点,系统已经提供了很好的api来做cell的缓存

                        [tableView dequeueReusableCellWithIdentifier:ID];

                        减少对象的创建和计算

               3、减少对象的属性赋值操作        

                        尤其是UIView的frame/bounds等属性的赋值操作,会产生比较大的CPU消耗。

                        对象的调整也经常是消耗 CPU 资源的地方。这里特别说一下 CALayer:CALayer 内部并没有属性,当调用属性方法时,它内部是通过运行时 resolveInstanceMethod 为对象临时添加一个方法,并把对应属性值保存到内部的一个 Dictionary 里,同时还会通知 delegate、创建动画等等,非常消耗资源。UIView 的关于显示相关的属性(比如 frame/bounds/transform)等实际上都是 CALayer 属性映射来的,所以对 UIView 的这些属性进行调整时,消耗的资源要远大于一般的属性。对此你在应用中,应该尽量减少不必要的属性修改。

    ——摘自iOS 保持界面流畅的技巧

                       所以在cell的layoutSubviews里布局所有子控件对性能是有影响的,对于frame固定的UIView,在cell创建时(或者懒加载方法里)布局一次即可。

                        另外,有时候一个tableview的cell的样式存在频繁的变化但又有一定的规律(比方说有一个label的高度总是在两行、一行来回变化),这就免不了会频繁的设置它的高度。如果追求很高的性能,可以筛分成两个cell,从而避免频繁的更改frame。(或者缓存高度 避免重新计算高度),对于固定高度的cell  尽量使用预设高度

                4、异步绘制

                      文本渲染、图像绘制都是比较消耗性能的操作,而UILabel等控件都是在主线程进行的文本绘制。这会对性能产生比较大的影响。

                     UIKit和CoreAnimation相关操作必须在主线程中进行,其它的可以在后台线程异步执行    异步绘制的思想,就是尽量把需要显示的内容,在异步线程绘制,绘制好后再通知主线程显示

                5、简化视图结构

                6、减少离屏渲染

                            gpu渲染一般是当前屏幕 但是一些操作需要在当前屏幕之外做渲染,在屏幕之外 需要创建 计算  渲染 非常消耗性能

                7.不要给cell动态添加subView

                8、在tableView:willDisplayCell:forRowAtIndexPath:这个方法中进行数据绑定。

                 tableview的高度计算问题 有个不错的文章   tableview优化

    6、NSProxy & NSObject

            NSProxy是一个实现了NSObject协议的根类

            1.多继承

            OC中类是不支持多继承的,要想实现多继承一般是有protocol的方式,还有一种就是利用NSProxy。有同学可能会问为什么不用NSObject来做?同样都是基类,都支持NSObject协议,NSProxy 有的NSObject 都有。但是点进NSProxy .h可以看见NSProxy没有init方法,而且NSProxy自身的方法很少,是一个很干净的类。这点很重要,因为NSObject自身的分类特别多,而消息转发的机制是当接收者无法处理时才会通过forwardInvocation:来寻求能够处理的对象.在日常使用时,我们很难避免不使用NSObject 的分类方法比如valueForKey这个方法NSObject就不会转发。

            结论: NSProxy更适合实现做为消息转发的代理类,实际操作中可用于模拟多重继承、AOP等      

            2.避免循环应用

                    这里举了比较常见了一个例子NSTimer.

                    由于目前苹果在iOS10以上,已经给出了timer 的block方式,已经可以解决循环引用的问题。所以demo举例只是说明利用NSProxy如何解决循环引用,大家在使用的时候可直接使用系统的方法。

             AOP面向切片编程

            iOS中面向切片编程一般有两种方式 ,一个是直接基于runtime 的method-Swizzling.还有一种就是基于NSProxy

            参考 aop

            NSObject

                1、加载及初始化类

                常用方法   `load`和`initialize`

                            `load`和`initialize`区别在于:`load`是只要类所在文件被引用就会被调用,而`initialize`是在类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目,就不会有`load`调用;但即使类文件被引用进来,但是没有使用,那么`initialize`也不会被调用;`load`每个类只会调用一次,`initialize`也只调用一次,但是如果子类没有实现`initialize`方法则会调用父类的方法,因此作为父类的`initialize`方法可能会调用多次。

                2、分配内存空间及初始化对象

                创建新对象时,首先调用`alloc`为对象分配内存空间,再调用`init`初始化对象,如`[[NSObject alloc] init]`;而`new`方法先给新对象分配空间然后初始化对象,因此`[NSObject new]`等同于`[[NSObject alloc] init]`;关于`allocWithZone`方法,官方文档解释该方法的参数是被忽略的,正确的做法是传nil或者NULL参数给它。

                3、给对象发送消息(执行方法)

                    1)直接调用

                   2)使用`performSelector`执行

                        使用`performSelector:`是运行时系统负责去找方法,在编译时候不做任何校验;因此在使用时必须先使用`respondsToSelector:`检查对象是否能调用方法,否则可能出现运行崩溃。`performSelector:`常用于调用运行时添加的方法,即编译时不存在,但是运行时候存在的方法。另外需要注意的是`performSelector:`系统提供最多接受两个参数的方法,而且参数和返回都是`id`类型,并不支持基础数据类型(如:int, float等)。

                    3)使用IMP指针调用

                       `SEL` 是方法的索引。IMP是函数指针,指向方法的地址。`SEL`与`IMP`是一一对应的关系,因此我们可以通过修改对应关系达到运行时方法交换的目的。

                        创建`SEL`对象两种方法:

                                    1、使用`@selector()`创建

                                    2、使用`NSSelectorFromString()`创建

                        获取方法`IMP`指针两种方法:

                        1、`- (IMP)methodForSelector:(SEL)aSelector;` 实例方法

                        2、`+ (IMP)instanceMethodForSelector:(SEL)aSelector;` 类方法

                4)、复制对象

                        `copy`拷贝为不可变对象,`mutableCopy`拷贝为可变变量,`copy`和`mutableCopy`都可理解为复制了一个新对象。虽然`copy`对静态对象只是引用计数加1,但是并不影响我们对复制前后的对象进行使用。需要注意的是对于容器对象而言,这两个方法只是复制了容器本身,对容器中包含的对象只是简单的指针引用,并没有深层复制。

                    如果想自定义类支持拷贝操作,那就要实现NSCopying协议(参考 copying

            5)、获取Class

                    调用 class 方法 获取当前对象的类

                    调用 superclass  获取父类

            6)、判断方法

                    // 判断对象是否继承NSObject

                    if ([student isProxy]) {

                            NSLog(@"student对象是继承NSObject类");

                     }

                    // 判断两个对象是否相等

                    if ([student isEqual:student2]) {

                                NSLog(@"student对象与student2对象相等");

                     }

                    // 判断对象是否是指定类

                    if ([person isKindOfClass:[ZMPerson class]]) {

                            NSLog(@"person对象是ZMPerson类");

                    }

                    // 判断对象是否是指定类或子类

                    if ([student isKindOfClass:[ZMPerson class]]) {

                                NSLog(@"student对象是ZMPerson类的子类");

                    }

                    // 判断是否是另一个类的子类

                    if ([ZMStudent isSubclassOfClass:[ZMPerson class]]) {

                            NSLog(@"ZMStudent类是ZMPerson类的子类");

                    }

                    // 判判断对象是否遵从协议

                    if ([student conformsToProtocol:@protocol(NSObject)]) {

                                NSLog(@"student对象遵循NSObject协议");

                   }

                    // 判断类是否遵从给定的协议

                    if ([ZMStudent conformsToProtocol:@protocol(NSObject)]) {

                            NSLog(@"ZMStudent类遵循NSObject协议");

                    }

                    // 判断对象是否能够调用给定的方法

                    if ([student respondsToSelector:@selector(running)]) {

                                NSLog(@"student对象可以调用‘running’方法");

                   }

                    // 判断实例是否能够调用给定的方法

                    if ([ZMStudent instancesRespondToSelector:@selector(running)]) {

                                NSLog(@"ZMStudent类可以调用‘running’方法");

                    }

            NSObject  只有一个成员变量是Class类型的isa变量   上面大部分方法都是NSObject协议里面的  Class是一个objc_class类型的结构体指针 

            我们都知道objc中id也是一种对象类型,那么它究竟是什么呢?看下面的定义

            typedef struct objc_object {

                    Class isa;

             } *id;

            原来id类型就是一个objc_object的一个结构体指针这个objc_object的结构体也仅仅包涵一个isa变量。

            总结:我们可以得出这样的结论,在objc的runtime中,类是用 objc_class 结构体表示的,对象是用 objc_object 结构体表示的。 对象的 isa 用来表示这个对象是哪个类的实例。

    7传值通知 & 推送通知(本地&远程)

            1)传值通知

                    注意事项:

                    在 iOS9 及其之后版本不用在dealloc移除通知,在此之前还是需要移除通知的

                    通知发送线程和通知接收线程是一致的。

                    如果当我们不是百分之百确认通知的发送队列是在主队列中时,我们最好在主线程对我们的UI进行处理。

                    传值通知

            2)推送通知

                    一般推送分本地推送和apns推送  注意权限问题 就可以了。

                    有篇不错的博客   消息推送

    9、第三方库 & 第三方平台

            1)常用的三方库:AFNetworking,SDWebImage,Masonry,MJRefresh,MJExtension

            2)常用的三方平台:友盟(三方登录,分享,崩溃日志采集)、growingIO(用户行为收集)、七牛(图片上传)

    10、NSCache & NSDcitionary

            NSCache    

            NSCache是Foundation框架提供的缓存类的实现,使用方式类似于可变字典,由于NSMutableDictionary的存在,很多人在实现缓存时都会使用可变字典,但NSCache在实现缓存功能时比可变字典更方便,最重要的是它是线程安全的,而NSMutableDictionary不是线程安全的,在多线程环境下使用NSCache是更好的选择。

            应用:

            SDWebImage中SDImageCache图片缓存   默认缓存一周

            AFNetworking(2.X)中UIImageView+AFNetworking的图片缓存   但是在AF 3.0及以上已经替换了实现的方式(NSMutableDictionary + GCD保证线程安全),有兴趣可以直接自己看一下3.0源码。

            NSCache详解            YYCache详解

            NSURLCache 这个主要是说的网络请求的缓存

            NSDictionary

                    NSDictionary(字典)是使用 hash表来实现key和value之间的映射和存储的, hash函数设计的好坏影响着数据的查找访问效率。数据在hash表中分布的越均匀,其访问效率越高。而在Objective-C中,通常都是利用NSString 来作为键值,其内部使用的hash函数也是通过使用 NSString对象作为键值来保证数据的各个节点在hash表中均匀分布。

                    对于字典  尽量避免重复的key  造成的hash冲突  增加查询时间

              hash浅谈

            NSDictionary使用NSMapTable实现,NSMapTable同样是一个key-value的容器。

            有两个字典,分别存有 100 条数据和 10000 条数据,如果用一个不存在的 key 去查找数据,在哪个字典中速度更快?

                    在 Redis 中,得益于自动扩容和默认哈希函数,两者查找速度一样快。在 Java 和 Objective-C 中,如果哈希函数不合理,返回值过于集中,会导致大字典更慢。Java 由于存在链表和红黑树互换机制,搜索时间呈对数级增长,而非线性增长。在理想的哈希函数下,无论字典多大,搜索速度都是一样快。

            既然知道了作为key值,必须遵循NSCopying协议,说明除了NSString对象之外,我们还可以使用其他类型对象来作为NSDictionary的 key值。不过这还不够,作为key值,该类型还必须继承于NSObject并且要重载一下两个方法

            - (NSUInteger)hash; 

             - (BOOL)isEqual:(id)object;

            其中,hash 方法是用来计算该对象的 hash 值,最终的 hash 值决定了该对象在 hash 表中存储的位置。所以同样,如果想重写该方法,我们尽量设计一个能让数据分布均匀的 hash 函数。(当存储大量重复度高的字符串  会大大增加hash碰撞,所以可能需要重新设计key)

            所以如果对象key的hash值相同,那在hash表里面的对应的value值是相同的(value值被更新了)

            isEqual方法是为了通过hash值来找到对象在hash表中的位置。

            NSMapTable

                    NSMapTable与NSDictionary/NSMutableDictionary对比

                    NSDcitionary有一个可变类型NSMutableDictionary,NSMapTable没有可变类型,它本身就是可变的;

                    NSDcitionary/NSMutableDictionary中对于key和value的内存管理方法唯一,即对key进行copy,对value进行强引用,而NSMapTable没有限制;

                    NSDcitionary中对key值进行copy,不可改变,通常用字符串作为key值,只是key->object的映射,而NSMapTable的key是可变的对象,既可以实现key->object的映射,又可以实现object->object的映射。

        NSSet  和  NSArray

                NSArray是有序的集合,NSSet是无序的集合。

                NSSet中不能存在重复的对象   底层是hash表实现的。

                NSSet查找一个值的时候效率更高 主要也是因为通过hash去定位位置的,快速查找。

                遍历 NSSet 采用  enumerateObjectsUsingBlock  枚举遍历 NSArray也可以采用枚举遍历  效率会高很多   反向查找 enumerateObjectsWithOptions  最快 

        11、UIView的setNeedsDisplay和setNeedsLayout方法

                setNeedsDisplay异步执行的。它会自动调用drawRect方法,这样可以拿到 UIGraphicsGetCurrentContext,就可以绘制了。而setNeedsLayout会默认调用layoutSubViews,处理子视图中的一些数据。

                setNeedsLayout

                此方法用来重新定义子元素的位置和大小。当子类重写此方法,用来实现UI元素的更精确布局。如果要让布局重新刷新,那么就调用setNeedsLayout,即setNeedsLayout方法会默认用layoutSubViews方法。

                很多时候系统会自动调用layoutSubviews方法:

                        1.初始化不会触发layoutSubviews,但是如果设置了不为CGRectZero的frame的时候就会触发。

                        2.addSubview会触发layoutSubviews

                        3.设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化

                        4.滚动一个UIScrollView会触发layoutSubviews

                        5.旋转Screen会触发父UIView上的layoutSubviews事件

                        6.改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件    

                         setNeedsLayout方法并不会立即刷新,立即刷新需要调用layoutIfNeeded方法(一般使用约束的时候 调一下可以立即更新效果)。

                         与setNeedsLayOut方法相似的方法是setNeedsDisplay方法。该方法在调用时,会自动调用drawRect方法。drawRect方法主要用来画图。

            总结

            所以,当需要刷新布局时,用setNeedsLayOut方法;当需要重新绘画时,调用setNeedsDisplay方法。

    12、CALayer & UIView

    主要区别:

           1) UIView是可以响应事件的,但是CALayer不能响应事件   因为UIView继承了 UIResponder     在 UIResponder中定义了处理各种事件和事件传递的接口, 而 CALayer直接继承 NSObject,并没有相应的处理事件的接口。

            2)UIView主要负责管理内容,而CALayer主要负责渲染和呈现。如果没有CALayer,我们是看不到内容的。

            3)CALayer维护着三个layer tree,分别是presentLayer Tree、modeLayer Tree、Render Tree,在做动画的时候,我们修改动画的属性,其实是修改presentLayer的属性值,而最终展示在界面上的其实是提供UIView的modelLayer。

            4)View和CALayer的Frame映射及View如何创建CALayer.

                    一个 Layer 的 frame 是由它的 anchorPoint,position,bounds,和 transform 共同决定的,而一个 View 的 frame 只是简单的返回 Layer的 frame,同样 View 的 center和 bounds 也是返回 Layer 的一些属性。

            5)在做 iOS 动画的时候,修改非 RootLayer的属性(譬如位置、背景色等)会默认产生隐式动画,而修改UIView则不会。

            uiview和calayer

    13)layoutSubViews & drawRects

            1) drawRects 

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

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

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

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

            使用 drawRects 需要注意内存问题  具体参考内存恶鬼 drawrect    使用 CAShaperLayer  替代 CALayer

    layoutSubViews

            调用之后会刷新布局   ,通过setNeedsLayOut调用.

    14、UDID & UUID

            UDID,是 iOS 设备的一个唯一识别码,每台 iOS 设备都有一个独一无二的编码,这个编码,我们称之为识别码.从iOS5之后,苹果就禁止了通过代码访问UDID,在目前的SDK中,苹果提供了一个参数identifierForVendor来替代原来UDID的作用.当然,和真正的UDID的区别是显而易见的:App的开发者没有办法去区分某一台设备了,而是只能识别某个应用在某台设备上。

            UUID含义是通用唯一识别码 (Universally Unique Identifier),这是一个软件建构的标准.

    15、CPU & GPU

            太高深,我的理解  一个主要处理逻辑运算,内存,另一个主要处理图形显示    大家参考这篇博客 cpu与gpu   还有一篇博客 感兴趣的可以去看看 gpu or cpu in ios

    16、点(pt)& 像素(px)

            iOS 开发中用到的单位 pt 是独立像素的意思,它是绝对长度,不随屏幕像素密度变化而变化(和我们日常用到的毫米、厘米是一个意思,只是它要小得多),在非视网膜的 iPhone 上(iPhone 3G),苹果规定 1px=1pt,也就是说 pt 和像素点是一一对应的。但随着 iPhone 4 的到来,高分屏出现了(视网膜屏),这个时候 1pt 对应 2px。所以用固定长度 pt 作为开发单位的好处是:这样可以统一图形在同一种类不同型号设备上图形的大小。而如果用像素作为单位的话,就乱了套了,因为在不同像素密度的屏幕里面,像素本身大小是不一样的。

    17、属性与成员变量

            区别

                    1).属性的默认修饰是@protected。

                    2).属性会自动生成set和get方法。

                    3).属性用点语法调用,点语法实际上调用的是set和get方法。

                    4).成员变量不能用点语法调用,因为没有set和get方法,只能使用->调用。

            成员变量是 通过@protected 修饰属性 会自动生成成员变量 _属性  在set和get方法里不能用self点语法

            iOS 中成员变量、实例变量、属性 区分

    18、int和NSInteger的区别

            int 是基本数据类型,   NSInteger 是一个对 int 做了一个封装   不用考虑设备是32位的还是64位的

            尽量使用 NSInteger 

        (1)import和include  (2)@class 

            都是引入头文件的作用 import不会引起交叉编辑 能用import就用import, @class  在.h文件尽量使用@class  

            1. import会包含这个类的所有信息,包括实体变量和方法(.h文件中),而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,后面会再告诉你。

            2. 在头文件中, 一般只需要知道被引用的类的名称就可以了。 不需要知道其内部的实体变量和方法,所以在头文件中一般使用@class来声明这个名称是类的名称。 而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。

            备注:#import 就是把被引用类的头文件走一遍,即把.h文件里的变量和方法包含进来一次,且仅一次,而@class不用,所以后者编译效率更高。

            3. 在编译效率方面考虑,如果你有100个头文件都#import了同一个头文件,或者这些文件是依次引用的,如A–>B, B–>C, C–>D这样的引用关系。当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,如果你的类有很多的话,这将耗费大量的时间。而是用@class则不会。

         (3)全局 & 静态变量

            全局变量:

            使用extern修饰的变量,是一个全局变量。

            a.函数外面声明

            b.可以跨文件访问

            c.可以在声明时赋上初始值

            d.存放在全局(静态)区的   

            与局部变量区别:

            全局变量保存在内存的全局存储区中,占用静态的存储单元;局部变量保存在栈中,只有在所在函数被调用时才动态地为变量分配存储单元。

            静态变量:

            使用 static修饰的变量,是一个私有的全局变量。

            static修饰的变量必须放在@implementation外面或方法中,它只在程序启动初始化一次。

            与全局变量相比,静态变量存储位置一样,声明位置如果也一样(函数外部),静态变量这时跟全局变量有什么区别?就是为了限制访问范围,静态变量仅当前声明该变量文件里面的代码可以访问。而全局变量可以同一工程跨文件访问,可能会引起严重的混淆问题。

            静态常量:

            const修饰的变量是不可变的,如果需要定义一个时间间隔的静态常量,就可以使用const修饰。

            深入研究Block捕获外部变量和__block实现原理

        19、类和对象

                类就是类似模板的东西  对象是通过类生成的具体的一个东西。

            (1)分类、拓展、协议中哪些可以声明属性?

                        都可以,但分类和协议创建的属性只相当于方法,但是内部没有对成员变量的操作(无法创建成员变量),拓展可以(私有成员变量)

                        代理中声明属性,没有实际创建成员变量,相当于声明了属性名对应的访问方法,遵守协议的类需要实现对应的访问器方法,否则运行报错

                        分类中声明属性,警告提示需要手动实现访问器方法(Swift中叫计算型属性),而分类中不能创建成员变量,可以在手写访问器方法中使用runtime的 objc_setAssociatedObject方法关联对象间接创建属性(静态库添加属性)

                        拓展里可以声明属性,直接可以使用

                        iOS-分类(Category)

            (2)继承和类别的区别

                        1> 使用继承:

                                1.1> 添加新方法和父类方法一致,但父类方法仍需要使用

                                1.2> 添加新属性

                        2> 类别:

                                2.1> 针对系统提供的一些类,系统本身不提倡继承,因为这些类的内部实现对继承有所限制(NSString initWithFormat继承崩溃)

                                2.2> 类别可以将自己构建的类中的方法进行分组,对于大型的类,提高可维护性

            (3)分类的作用

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

                                创建对私有方法的前向引用。

                                向对象添加非正式协议。

                                        (非正式协议:即NSObject的分类,声明方法可以不实现,OC2.0以前protocal没有@optional,主要使用分类添加可选协议方法

                                oc中声明方法不实现,不调用则只警告不报错

                            正式协议的优点:可继承,泛型约束

                            如kvo的observeValueForKeyPath属于nsobject的分类,且不需要调父类,说明可选实现该方法,没警告可能是编译器规则过滤)

            (4)分类的局限性

                            无法向类中添加新的实例变量,类别没有位置容纳实例变量。

                            名称冲突,即当类别中的方法与原始类方法名称冲突时,类别具有更高的优先级。类别方法将完全取代初始方法从而无法再使用初始方法。

                            无法添加实例变量的局限可以使用字典对象解决

    20、category & extension

            分类、扩展区别

                    ①分类中原则上只能增加方法(能添加属性的的原因只是通过runtime解决无setter/getter的问题而已);

                    ②类扩展不仅可以增加方法,还可以增加实例变量(或者属性),只是该实例变量默认是@private类型的(

            用范围只能在自身类,而不是子类或其他地方);

                    ③类扩展中声明的方法没被实现,编译器会报警,但是类别中的方法没被实现编译器是不会有任何警告的。这是因为类扩                    展是在编译阶段被添加到类中,而类别是在运行时添加到类中。

                    ④类扩展不能像类别那样拥有独立的实现部分(@implementation部分),也就是说,类扩展所声明的方法必须依托对应类的实现部分来实现。

                    ⑤定义在 .m 文件中的类扩展方法为私有的,定义在 .h 文件(头文件)中的类扩展方法为公有的。类扩展是在 .m 文件中声明私有方法的非常好的方式。

      21、Foundation

                    iOS Foundation 框架简介

                   oc中主要的两个框架  一个Foundation  一个UIKit

                (1)字符串

                         NSString和NSMutableString    如果使用一个经常改变的字符串  尽量使用NSMutableString 。不可变字符串有很多好处,最重要的一个就是多线程安全,因为不可变,所以任何线程都可以随意使用它。

                        具体实现 类簇   具体可以参考  iOS中类簇的使用

                (2)字符串截取

                        常用的方法

                            a.  substringToIndex  从字符串开始截取到指定的位置,是从0开始.  不包含结束位置

                            b.  substringFromIndex   从指定位置截取到字符串结尾  包含起始位置

                            c.  substringWithRange   截取指定的范围

                (3)格式

            22、NSArray和NSDictionary

                    (1)iOS遍历数组/字典的方法

                                数组:for循环,   for in 循环,   枚举循环

                                字典:获取所有key  然后for循环  ,for in循环 ,枚举循环(可以反向循环)

                    (2)NSValue NSNumber

                                一个NSValue对象是用来存储一个C或者Objective-C数据的简单容器。它可以保存任意类型的数据,比如int,float,char,当然也可以是指pointers, structures, and object ids。NSValue类的目标就是允许以上数据类型的数据结构能够被添加到集合里,例如那些需要其元素是对象的数据结构,如NSArray或者NSSet的实例。需要注意的是NSValue对象一直是不可枚举的

                                  NSNumber与NSValue关系与作用

                    (3)其它

                    (4)如何避免循环引用

                                记一下:NSArray强引用、弱引用          

            23、CFSocket使用有哪几个步骤

                        0.(可选)创建CFSocketContext->用来关联Socket上下文信息

                        1.创建CFSocket对象

                        2.创建Socket需要连接的地址,这是一个结构体,需要包含几个参数,同事IPV4和IPV6不一样

                        3.把地址转换成CFDataRef

                        4.连接

                                这里连接有2种方案:

                                方案一:

                                        如果上面SocketRef创建爱你时候选择回调类型为kCFSocketNoCallBack,然后没有设置回调函数,那就直接进行连接

                               方案二:

                                        如果设置回调参数为kCFSocketConnectCallBack,并且设置了回调函数

                      5.连接成功和失败的判断

                      6.读取数据

                      7.向服务端上传数据

                     CFSocket学习

                    常用的socket框架  mqtt、xmpp

                    理解socket  三次握手

                    理解CFNetwork、CFStream

            24、Core Foundation中提供了哪几种操作Socket的方法?

                    CFNetwork 、 CFSocket 和 BSD Socket 。

            25、解析XML文件有哪几种方式?

                    DOM:一次性将整个XML数据加载进内存进行解析,比较适合解析小文件

                    SAX:从根元素开始,按顺序一个元素一个元素往下解析,比较适合解析大文件

             26、什么是沙盒模型?哪些操作是属于私有api范畴?      

                    应用程序沙盒目录

                            应用程序包:和app同名,包含所有资源文件和可执行文件

                            Document:存放其中的数据会备份到icloud,不允许放下载的数据。用户自行生成的文件放入其中

                            Library

                            caches:用于存放一些缓存数据,保存应用运行时生成的需要持久化的数据

                            preference:存储偏好信息,苹果手机的设置应用会在该目录中查找应用的设置信息

                            tmp:临时文件夹,不定期删除

                    私有api:常见比如直接发送短信,访问沙箱之外的磁盘文件

             27、在一个对象的方法里面:self.name= “object”;和 name =”object” 有什么不同吗?

                               self.name= “object”   是调用set方法 给成员变量赋值     

                                name =”object”   就是一个简单的赋值语句

            28、请简要说明viewDidLoad和viewDidUnload何时调用

                         viewDidUnload方法在ios6中已经被舍弃

                        当一个视图控制器被创建,并在屏幕上显示的时候。 代码的执行顺序

                                1、 alloc                                   创建对象,分配空间

                                2、init (initWithNibName) 初始化对象,初始化数据

                                3、loadView                          从nib载入视图 ,通常这一步不需要去干涉。除非你没有使用xib文件创建视图

                                4、viewDidLoad                   载入完成,可以进行自定义数据以及动态创建其他控件

                                5、viewWillAppear              视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了

                                6、viewDidAppear               视图已在屏幕上渲染完成

                        当一个视图被移除屏幕并且销毁的时候的执行顺序,这个顺序差不多和上面的相反

                                1、viewWillDisappear            视图将被从屏幕上移除之前执行

                                2、viewDidDisappear             视图已经被从屏幕上移除,用户看不到这个视图了

                                3、dealloc                                 视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放

    相关文章

      网友评论

          本文标题:iOS常用面试题一

          本文链接:https://www.haomeiwen.com/subject/fqzjjqtx.html