iOS知识点(一)

1. 什么是arc?(arc是为了解决什么问题诞生的?)

  • ARC的全称是Automatic Reference Counting(自动引用计数)
  • ARC是自iOS 5之后增加的新特性,不需要程序员管理内容, 编译器会在适当的地方自动给我们添加release/retain等代码(主要针对内存泄露)

相关知识:
1.与ARC相对的是MRC, 手动引用计数, 可以简称MRC (Manual Reference Counting) 所有对象的内容都需要我们手动管理, 需要程序员自己编写release/retain等代码
2.ARC的判断原则:只要没有强指针指向对象,对象就会被释放。
(1)强指针:默认的情况下,所有的指针都是强指针,关键字strong
(2)弱指针:_ _weak关键字修饰的指针
3.ARC的特点总结:
(1)不允许调用release,retain,retainCount
(2)允许重写dealloc,但是不允许调用[super dealloc]
(3)@property的参数:
Strong:相当于原来的retain(适用于OC对象类型),成员变量是强指针
Weak:相当于原来的assign,(适用于oc对象类型),成员变量是弱指针
Assign:适用于非OC对象类型(基础类型)

2. 请解释以下keywords的区别: assign vs weak, __block vs__weak

  • weak和assign都是引用计算不变,两个的差别在于,weak用于指针类型,而assign用于简单的数据类型,如int BOOL 等。
  • assign看起来跟weak一样,其实不能混用的,assign的变量在释放后并不设置为nil(和weak不同),当你再去引用时候就会发生错误,崩溃,EXC_BAD_ACCESS.
  • __block 是通过引用来访问self的实例变量,block也是一个强引用,self被retain,引起循环引用,用__weak是弱引用,当self释放时,weakSelf已经等于nil

相关知识
在垃圾回收机制里面,如果你同时使用__weak__block来标识一个变量,那么该block将不会保证它是一直是有效的。 如果你在实现方法的时候使用了block,对象的内存管理规则更微妙:也是(__weak__block区别:)
(1)如果你通过引用来访问一个实例变量,self会被retain。
(2)如果你通过值来访问一个实例变量,那么变量会被retain

扩展:NSTimer注意避免循环引用的地方,需要找个合适的时机和地方来 invalidate timer
在引用计数的环境里面,默认情况下当你在block里面引用一个Objective-C对象的时候,该对象会被retain。当你简单的引用了一个对象的实例变量时,它同样被retain。但是被__block存储类型修饰符标记的对象变量不会被retain

3. __block在arc和非arc下含义一样吗?

  • 对于非ARC下, 为了防止循环引用, 我们使用__block来修饰在Block中使用的对象:
  • 对于ARC下, 为了防止循环引用, 我们使用__weak来修饰在Block中使用的对象。原理就是:ARC中,Block中如果引用了__strong修饰符的自动变量,则相当于Block对该变量的引用计数+1。
    <解决循环引用问题>
//非ARC
__block typeof(self) weakSelf = self;
self.myBlock = ^(int paramInt){ 
//使用weakSelf访问self成员
 [weakSelf anotherFunc];
};

4. 使用atomic一定是线程安全的吗?

  • 当然不是。
    atomic在set方法里加了锁,防止了多线程一直去写这个property,造成难以预计的数值, 但这也只是读写的锁定, 线程安全其实还是差一些。

atomic有个很大的问题是很慢,要比nonatomic慢20倍。
当然最后建议这种数值数值变化可以让服务器来做

5. 描述一个你遇到过的retaincycle例子。

  • retain cycle 会造成内存溢出,严重情况会引起崩溃。一般注意点也不会发生,但在网络连接比较多的地方就会不小心出现,vc异步的网络请求,成功后的block调用vc,如果此时,用户已经不用此vc了,vc还是没有释放。

一个下拉刷新,那个view和vc互相强引用,导致了没释放。view回去调用vc的scrollview的contentoffset

6. +(void)load; +(void)initialize;有什么用处?

  • 当类对象被引入项目时, runtime 会向每一个类对象发送 load 消息, 并且会在每一个类甚至分类被引入时仅调用一次,(调用的顺序是父类优先于子类, 子类优先于分类) 而且每一个类中的 load 方法都不需要像 viewDidLoad 方法一样调用父类的方法.

举个例子:
由于 load 方法会在类被 import 时调用一次, 而这时往往是改变类的行为的最佳时机. 我在 DKNightVersion 中使用 method swizlling 来修改原有的方法时, 就是在分类 load 中实现的.

  • initialize 方法和 load 方法有一些不同, 它虽然也会在整个 runtime 过程中调用一次, 但是它是在该类的第一个方法执行之前调用, 也就是说 initialize 的调用是 <惰性> 的, 它的实现也与我们在平时使用的惰性初始化属性时基本相同.

我在实际的项目中并没有遇到过必须使用这个方法的情况, 在该方法中主要做 静态变量的设置 并用于 确保在实例初始化前某些条件必须满足 .

7. 为什么其他语言里叫函数调用,objective-c语言里则是给对象发消息(或者谈下对runtime的理解)

  • 我们在其他语言中比如说: C, Python, Java, C++, Haskell ... 中提到函数调用或者方法调用(面向对象). 函数调用是在编译期就已经决定了会调用哪个函数(方法), 编译器在编译期就能检查出函数的执行是否正确.

**然而 Objective-C(ObjC) 是一门动态的语言, 整个 ObjC 语言都是尽可能的将所有的工作推迟到运行时才决定. 它基于 runtime 来工作, runtime 就是 ObjC 的灵魂, 其核心就是消息发送 objc_msgSend **

  • 所有的消息都会在运行时才会确定,[obj message]在运行时会被转化为objc_msgSend(id self, SEL cmd, ...)来执行, 它会在运行时从 选择子表中寻找对应的选择子 并将选择子与实现进行绑定. 而如果没有找到对应的实现, 就会进入类似黑魔法的消息转发流程. 调用 + (BOOL)resolveInstanceMethod:(SEL)aSelector方法, 我们可以在这个方法中 为类动态地生成方法 .

我们几乎可以使用 runtime 修改 Objective-C 中的一切:
*class property object ivar method protocol *

8. 什么是methodswizzling?

  • method swizzling 实际上就是一种在运行时动态修改原有方法的技术, 它实际上是基于 ObjC runtime的特性, 而 method swizzling 的核心方法就是 method_exchangeImplementations(SEL origin, SEL swizzle)使用这个方法就可以在运行时动态地改变原有的方法实现

在DKNigtVersion (为iOS应用添加夜间模式) 中能够看到大量 method swizzling 的使用, 方法的调用时机就是在上面提到的 load 方法中, 不在 initialize 方法中改变方法实现的原因是 initialize 可能会被子类所继承并重新执行最终导致错误 , 而 load 并不会被继承并重新执行.

9. UIView和CALayer是啥关系?

  • 每一个 UIView 的身后对应一个 Core Animation 框架中的 CALayer.

在 iOS 上 当你处理一个一个有一个的 UIView 时实际上是在操作 CALayer . 尽管有的时候你并不知道 (直接操作 CALayer 并不会在对效率有着显著的提升).

  • UIView 实际上就是对 CALayer 的轻量级的封装. UIView 继承自 UIResponder 处理来自用户的事件; CALayer 继承自 NSObject 主要用于图层的渲染和动画. 设计原因:

1.你可以通过操作 UIView 在一个更高的层级上处理与用户的交互, 触摸, 点击, 拖拽等事件, 这些都是在 UIKit 这个层级上完成的.
2.UIView 和 NSView(AppKit) 的实现极其不同, 而使用 Core Animation 可以实现底层代码地重用, 因为在 Mac 和 iOS 平台上都使用着近乎相同的 Core Animation 代码, 这样我们可以对这个层级进行抽象在两种平台上产生 UIKit 和 AppKit 用于不同平台的框架.
3.使用 CALayer 的唯一原因大概是便于移植到不同的平台, 如果仅仅使用 Core Animation 层级, 处理用户的交互时间需要写更多的代码.

10. 如何高性能的给UIImageView加个圆角?
(不准说layer.cornerRadius!)

  • 一般情况下给 UIImageView 或者说 UIKit 的控件添加圆角都是改变 clipsToBounds 和 layer.cornerRadius, 这样大约两行代码就可以解决. 但是, 这样使用这样的方法会 强制 Core Animation提前渲染屏幕的离屏绘制 , 而离屏绘制就会为性能带来负面影响.

<贝塞尔曲线> 可以完美解决

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];  
imageView.center = CGPointMake(200, 300);  
UIImage *anotherImage = [UIImage imageNamed:@"image"];  
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);  
[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds
  cornerRadius:50] addClip];
[anotherImage drawInRect:imageView.bounds];
imageView.image = UIGraphicsGetImageFromCurrentImageContext();  
UIGraphicsEndImageContext();  
[self.view addSubview:imageView];

11. 使用drawRect有什么影响?(这个可深可浅,你至少得用过。。)

  • 这个方法的主要作用是根据传入的 rect 来绘制图像,我们还可以在这个方法中使用 Core Graphics 和 UIKit 来绘制视图的内容.

  • 这个方法的调用机制也是非常特别. 当你调用 setNeedsDisplay 方法时, UIKit 将会把当前图层标记为 dirty, 但还是会显示原来的内容, 直到下一次的视图渲染周期, 才会重新建立 Core Graphics 上下文, 然后将内存中的数据恢复出来, 使用 CGContextRef 进行绘制.

12. ASIHttpRequest或者SDWebImage里面给
UIImageView加载图片的逻辑是什么样的?(把
UIImageView放到UITableViewCell里面问更赞)

  • SDWebImage 中为 UIView 提供了一个分类叫做 WebCache, 这个分类中有一个最常用的接口, sd_setImageWithURL:placeholderImage: , 这个分类同时提供了很多类似的方法, 这些方法最终会调用一个同时具有 optionprogressBlockcompletionBlock 的方法, 而在这个类最终被调用的方法首先会检查是否传入了placeholderImage以及对应的参数,并设置
    placeholderImage

  • 然后获取SDWebImageManager中的单例调用一个

    •          ``downloadImageWithURL:...``  的方法来获取图片, 而这个manager 获取图片的过程有大体上分为两部分:
      

首先会在 SDWebImageCache 中寻找图片是否有对应的缓存, 它会以 url 作为数据的索引先在内存中寻找是否有对应的缓存, 如果缓存未命中就会在磁盘中利用 MD5 处理过的 key 来继续查询对应的数据, 如果找到了, 就会把磁盘中的缓存备份到内存中.

然而, 假设我们在内存和磁盘缓存中都没有命中, 那么manager就会调用 SDWebImageDownloader 对象的方法downloadImageWithURL:...来下载图片, 过程中调用另一个方法:
addProgressCallback:andCompletedBlock:fotURL:createCallback:来存储下载过程中和下载完成的回调, 当回调块是第一次添加的时候, 方法会实例化一个 NSMutableURLRequest 和 SDWebImageDownloaderOperation , 并将后者加入 downloader 持有的下载队列开始图片的异步下载.

  • 而在图片下载完成之后, 就会在主线程设置 image, 完成整个图像的异步下载和配置.

13. 麻烦你设计个简单的图片内存缓存器(移除策略是一定要说的)

图片的内存缓存,可以考虑将图片数据保存到一个数据模型中。所以在程序运行时这个模型都存在内存中。
移除策略:释放数据模型对象。

14. 讲讲你用Instrument优化动画性能的经历吧(别问我什么是Instrument)

考虑程序的性能,可以借助数据化图形化的输出方式。与其花费时间在优化小细节上不如多点时间找到你改优化的地方.时间事件查看器 ——> Time Profiler打开Instrument的步骤:xcode ——> open developer Tool ——> instrument 选取相应的strumnet的工具,选择相应的strument里面的工具,然后选择模拟器或者真机上面的应用,点击右上角的开始按钮,然后就可以看到相应内容

Instrument详细介绍

15. loadView是干嘛用的?

  • 当你访问一个ViewController的view属性时,如果此时view的值是nil,那么,ViewController就会自动调用loadView这个方法。这个方法就会加载或者创建一个view对象,赋值给view属性。

loadView默认做的事情是:如果此ViewController存在一个对应的nib文件,那么就加载这个nib。否则,就创建一个UIView对象。
如果你用Interface Builder来创建界面,那么不应该重载这个方法。
如果你想自己创建view对象,那么可以重载这个方法。此时你需要自己给view属性赋值。你自定义的方法不应该调用super。如果你需要对view做一些其他的定制操作,在viewDidLoad里面去做。

  • 根据上面可以知道,有两种情况:

1、如果你用了nib文件,重载这个方法就没有太大意义。因为loadView的作用就是加载nib。如果你重载了这个方法不调用super,那么nib文件就不会被加载。如果调用了super,那么view已经加载完了,你需要做的其他事情在viewDidLoad里面做更合适。
2、如果你没有用nib,这个方法默认就是创建一个空的view对象。如果你想自己控制view对象的创建,例如创建一个特殊尺寸的view,那么可以重载这个方法,自己创建一个UIView对象,然后指定 self.view = myView; 但这种情况也没有必要调用super,因为反正你也不需要在super方法里面创建的view对象。如果调用了super,那么就是浪费了一些资源而已

16. viewWillLayoutSubView你总是知道的。

横竖屏切换的时候,系统会响应一些函数,其中
viewWillLayoutSubviews 和 viewDidLayoutSubviews。

- (void)viewWillLayoutSubviews  {   
   [self _shouldRotateToOrientation:(UIDeviceOrientation)[UIApplication sharedApplication].statusBarOrientation];  
}  
-(void)_shouldRotateToOrientation:(UIDeviceOrientation)orientation {  
   if (orientation == UIDeviceOrientationPortrait ||orientation ==UIDeviceOrientationPortraitUpsideDown) {
// 竖屏 }
 else {
// 横屏     } 
}
- (NSUInteger)supportedInterfaceOrientations{
    // 切换横屏
    return UIInterfaceOrientationMaskLandscape;
}

通过上述一个函数就知道横竖屏切换的接口了。
注意:viewWillLayoutSubviews只能用在ViewController里面,在view里面没有响应。

17. GCD里面有哪几种Queue?你自己建立过串行queue吗?背后的线程模型是什么样的?

  • 1.主队列 dispatch_main_queue(); 串行 ,更新UI
    2.全局队列 dispatch_global_queue(); 并行,四个优先级:background,low,default,high
    3.自定义队列 dispatch_queue_t queue ; 可以自定义是并行:DISPATCH_QUEUE_CONCURRENT
    或者串行DISPATCH_QUEUE_SERIAL

18. 用过coredata或者sqlite吗?读写是分线程的吗?遇到过死锁没?咋解决的?

  • 数据库读取操作一般都是多线程访问的。在对数据进行读取时,我们要保证其当前状态不能被修改,即读取时加锁,否则就会出现数据错误混乱。
    IOS中常用的两种数据持久化存储方式:CoreData和SQLite,两者都需要设置线程安全

19. http的post和get啥区别?(区别挺多的,麻烦多说点)

GET和POST与数据如何传递没有关系, GET和POST是由HTTP协议定义的。在HTTP协议中,Method和Data(URL, Body, Header)是正交的两个概念,也就是说,使用哪个Method与应用层的数据如何传输是没有相互关系的。HTTP没有要求,如果Method是POST数据就要放在BODY中。也没有要求,如果Method是GET,数据(参数)就一定要放在URL中而不能放在BODY中.

  • 1.(1) GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连,如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0%E5%A5%BD。如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密,得出如:%E4%BD%A0%E5%A5%BD,其中%XX中的XX为该符号以16进制表示的ASCII。
    (2) POST把提交的数据则放置在是HTTP包的包体中。
  • 2 . HTTP协议对GET和POST都没有对长度的限制

(1).首先是”GET方式提交的数据是有字节限制的”,因为GET是通过URL提交数据,那么GET可提交的数据量就跟URL的长度有直接关系了。其限制取决于操作系统的支持。
  注意这是限制是整个URL长度,而不仅仅是你的参数值数据长度。
 (2).理论上讲,POST是没有大小限制的,HTTP协议规范也没有进行大小限制,POST数据是没有限制的,起限制作用的是服务器的处理程序的处理能力。

  • 3.POST的安全性要比GET的安全性高,其实没有丝毫关系。对于GET和POST的理解,是纯粹地来源于HTTP协议。他们只有一点根本区别,简单点儿说,一个用于获取数据,一个用于修改数据

20. 我知道你大学毕业过后就没接触过算法数据结构了,但是请你一定告诉我什么是Binary search tree? search的时间复杂度是多少?我很想知道!

  • Binary search tree:二叉搜索树。
    主要由四个方法:(用C语言实现或者Python)
    1.search:时间复杂度为O(h),h为树的高度
    2.traversal:时间复杂度为O(n),n为树的总结点数。
    3.insert:时间复杂度为O(h),h为树的高度。
    4.delete:最坏情况下,时间复杂度为O(h)+指针的移动开销。

可以看到,二叉搜索树的dictionary operation的时间复杂度与树的高度h相关。所以需要尽可能的降低树的高度,由此引出平衡二叉树Balanced binary tree。它要求左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。这样就可以将搜索树的高度尽量减小。常用算法有红黑树、AVL、Treap、伸展树等。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • iOS网络架构讨论梳理整理中。。。 其实如果没有APIManager这一层是没法使用delegate的,毕竟多个单...
    yhtang阅读 5,160评论 1 23
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,121评论 29 470
  • 基础 1. 为什么说Objective-C是一门动态的语言? 2. 讲一下MVC和MVVM,MVP? 3. 为...
    波妞和酱豆子阅读 3,301评论 0 46
  • 1.属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作...
    曾令伟阅读 1,042评论 0 10
  • cookie cookie是什么?用来保存用户信息 自动登录、记住用户名 cookie的特性 1.同一个网站所有页...
    pizan阅读 259评论 0 0