assign和weak的区别 和 dispatch的区别是什么

iOS面试题-iOS部分_9347481_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
iOS面试题-iOS部分_9347481
上传于||暂无简介
阅读已结束,如果下载本文需要使用
想免费下载本文?
下载文档到电脑,查找使用更方便
还剩16页未读,继续阅读
你可能喜欢iOS中assign,copy,retain之间的区别以及weak和strong的区别_百度知道
iOS中assign,copy,retain之间的区别以及weak和strong的区别
提问者采纳
&#8226,这个对象的 retain 值+1assign 地址还是0x1111?Copy 其实是建立了一个相同的对象,指针拷贝); assign。&#8226:
简单的直接赋值,再提高输入对象的索引计数 为1那上面的是什么意思呢,内容也还是“ABC”,地址为 0×2222,而 retain 不是; 和 @property (copy) SomeClass * aObject,内容为@”ABC”Copy 到另外一个 NSString 之 后,weak 用来修饰属性, 旧 有对象没有变化retain 到另外一个 NSString 之 后,其他的也跟着改变,而不是值自身的情况,一个地方变了不影响另一个地方的对象,地址为 0×1111; weak 用来修饰弱引用的属性; 对应原来的 @property (assign) SomeClass * aObject,copy 是内容拷贝; retain。strong 用来修饰强引用的属性:释放旧的对象,将旧对象的值赋予输入对象,相当于说两个对象指向同个内存区。strong;@property (weak) SomeClass * aObject: 用于希望保持一份传入值的拷贝,重新加载一内存区;@property (strong) SomeClass * aO 对应原来的 @property (retain) SomeClass * aObject,地址相同(建立一个指针,内容当然相 同,内容相同,retain 是指针拷贝,一个地方的变了。也就是说,即把原来的对象完整的赋值到另外一地方,新的对象 retain 为 1:比如一个 NSString 对象; copy&#8226
来自团队:
其他类似问题
为您推荐:
assign的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁关于一些 iOS 面试问题的解答 - 推酷
关于一些 iOS 面试问题的解答
这篇 post 主要是对知乎上
的回答, 也算是对自己已有的知识进行整理.
如果你对本篇 post 中的回答有所疑问, 可以在下面留言. 如果有问题, 我一定会修改的 :-)
问题以及回答
1. 什么是 ARC? (ARC 是为了解决什么问题而诞生的?)
ARC 是 Automatic Reference Counting 的缩写, 即自动引用计数. 这是苹果在 iOS5 中引入的内存管理机制. Objective-C 和 Swift 使用 ARC 追踪和管理应用的内存使用. 这一机制使得开发者无需键入
, 这不仅能够降低程序崩溃和内存泄露的风险, 而且可以减少开发者的工作量, 能够大幅度提升程序的
. 但是 ARC 不适用于 Core Foundation 框架中, 仍然需要手动管理内存.
2. 以下 keywords 有什么区别:
assign vs weak
__block vs __weak
是用于在声明属性时, 为属性指定内存管理的语义.
用于简单的赋值, 不改变属性的引用计数, 用于 Objective-C 中的
以及 C 语言中
等数据类型.
用于对象类型, 由于
同样不改变对象的引用计数且不持有对象实例, 当该对象废弃时, 该弱引用自动失效并且被赋值为
, 所以它可以用于避免两个强引用产生的
导致内存无法释放的问题.
之间的却是确实极大的, 不过它们都用于修饰变量.
前者用于指明当前声明的变量在被 block 捕获之后, 可以在 block 中改变变量的值. 因为在 block 声明的同时会截获该 block 所使用的全部自动变量的值, 而这些值只在 block 中
只具有&使用权&而不具有&修改权&
说明符就为 block 提供了变量的修改权.
所有权修饰符
, 什么是所有权修饰符? 这里涉及到另一个问题, 因为在 ARC 有效时, id 类型和对象类型同 C 语言中的其他类型不同, 必须附加所有权修饰符. 所有权修饰符一种有 4 种:
__unsafe_unretained
__autorelease
的区别只在于, 前者用于变量的声明, 而后者用于属性的声明.
在 ARC 和非 ARC 下含义一样吗?
在 ARC 下捕获的变量会被 block retain
, 这样可能导致循环引用, 所以必须要使用弱引用才能解决该问题. 而在非 ARC 下, 可以直接使用
说明符修饰变量, 因为在非 ARC 下, block 不会 retain 捕获的变量.
一定是线程安全的吗?
的内存管理语义是
的, 非原子的操作本来就是线程不安全的, 而
的操作是原子的, 但是
并不意味着它是线程安全的
, 它会增加正确的几率, 能够更好的避免线程的错误, 但是它仍然是线程不安全的.
的时候, 属性的 setter 和 getter 操作是非原子的, 所以当多个线程同时对某一属性进行读和写的操作, 属性的最终结果是不能预测的.
时, 虽然对属性的读和写是原子的, 但是仍然可能出现线程错误: 当线程 A 进行写操作, 这时其他线程的读或写操作会因为该操作的进行而等待. 当 A 线程的写操作结束后, B 线程进行写操作, 然后当 A 线程进行读操作时, 却获得了在 B 线程中的值, 这就破坏了线程安全, 如果有线程 C 在 A 线程读操作前 release 了该属性, 那么还会导致程序崩溃. 所以仅仅使用
并不会使得线程安全, 我们还需要为线程添加
来确保线程的安全.
都不是一定线程安全的,
就更不必多说了.
描述一个你遇到过的 retain cycle 例子.
有什么用处?
当类对象被引入项目时, runtime 会向每一个类对象发送
方法还是非常的神奇的, 因为它会在
每一个类甚至分类
被引入时仅调用一次, 调用的顺序是父类优先于子类, 子类优先于分类. 而且
方法不会被类自动继承, 每一个类中的
方法都不需要像
viewDidLoad
方法一样调用父类的方法. 由于
方法会在类被
时调用一次, 而这时往往是改变类的行为的最佳时机. 我在
method swizlling
来修改原有的方法时, 就是在分类
initialize
方法有一些不同, 它虽然也会在整个 runtime 过程中调用一次, 但是它是在
该类的第一个方法执行之前
调用, 也就是说
initialize
的, 它的实现也与我们在平时使用的惰性初始化属性时基本相同. 我在实际的项目中并没有遇到过必须使用这个方法的情况, 在该方法中主要做
静态变量的设置
确保在实例初始化前某些条件必须满足
7. 为什么其他语言里叫函数调用, Objective-C 中是给对象发送消息 (谈下对 runtime 的理解)
我们在其他语言中比如说: C, Python, Java, C++, Haskell ... 中提到函数调用或者方法调用(面向对象). 函数调用是在编译期就已经决定了会调用哪个函数(方法), 编译器在编译期就能检查出函数的执行是否正确.
然而 Objective-C(ObjC) 是一门动态的语言, 整个 ObjC 语言都是尽可能的将所有的工作推迟到运行时才决定. 它基于 runtime 来工作, runtime 就是 ObjC 的灵魂, 其核心就是消息发送
objc_msgSend
What makes Objective-C truly powerful is its runtime.
所有的消息都会在运行时才会确定,
[obj message]
在运行时会被转化为
objc_msgSend(id self, SEL cmd, ...)
来执行, 它会在运行时从
选择子表中寻找对应的选择子
并将选择子与实现进行绑定. 而如果没有找到对应的实现, 就会进入类似黑魔法的消息转发流程. 调用
+ (BOOL)resolveInstanceMethod:(SEL)aSelector
方法, 我们可以在这个方法中
为类动态地生成方法
我们几乎可以使用 runtime 魔改 Objective-C 中的一切:
, 而下面就是它的主要应用:
为分类动态的添加属性
使用方法调剂修改原有的方法实现
8. 什么是 Method Swizzling?
method swizzling
实际上就是一种在运行时动态修改原有方法的技术, 它实际上是基于 ObjC runtime 的特性, 而
method swizzling
的核心方法就是
method_exchangeImplementations(SEL origin, SEL swizzle)
. 使用这个方法就可以在运行时动态地改变原有的方法实现, 在
(为 iOS 应用添加夜间模式) 中能够看到大量
method swizzling
的使用, 方法的调用时机就是在上面提到的
方法中, 不在
initialize
方法中改变方法实现的原因是
initialize
可能会被子类所继承并重新执行最终导致错误
并不会被继承并重新执行.
有什么关系?
看到这个问题不禁想到大一在网易面试时的经历, 当时的两位面试官就问了我这么一个问题,
是什么关系, 为什么要这么设计? 我已经忘记了当时是怎么回答的. 隐约记得当时说每一个
都会对应一个
至于为什么这样, 当时的我实在是太弱无法回答出来了.
的身后对应一个
Core Animation
Many of the methods you call on UIView simply delegate to the layer
在 iOS 上 当你处理一个一个有一个的
时实际上是在操作
. 尽管有的时候你并不知道 (直接操作
并不会在对效率有着显著的提升).
实际上就是对
的轻量级的封装.
UIResponder
处理来自用户的事件;
主要用于图层的渲染和动画. 这么设计有以下几个原因:
你可以通过操作
在一个更高的层级上处理与用户的交互, 触摸, 点击, 拖拽等事件, 这些都是在
这个层级上完成的.
NSView(AppKit)
的实现极其不同, 而使用
Core Animation
可以实现底层代码地重用, 因为在 Mac 和 iOS 平台上都使用着近乎相同的
Core Animation
代码, 这样我们可以对这个层级进行抽象在两种平台上产生
用于不同平台的框架.
的唯一原因大概是便于移植到不同的平台, 如果仅仅使用
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];
在这里使用了贝塞尔曲线&切割&个这个图片, 给
UIImageView
添加了的圆角.
有什么影响?
这个问题对于我来说确实有些难以回答, 我记得我在我人生的第一个 iOS 项目 SportJoin 中曾经使用这个方法来绘制图形, 但是具体怎么做的, 我已经忘记了.
这个方法的主要作用是根据传入的
来绘制图像
. 这个方法的默认实现没有做任何事情, 我们
在这个方法中使用
Core Graphics
来绘制视图的内容.
这个方法的调用机制也是非常特别. 当你调用
setNeedsDisplay
方法时, UIKit 将会把当前图层标记为 dirty, 但还是会显示原来的内容, 直到下一次的视图渲染周期, 才会重新建立 Core Graphics 上下文, 然后将内存中的数据恢复出来, 使用 CGContextRef 进行绘制.
12. ASIHttpRequest 或者 SDWebImage 里面给 UIImageView 加载图片的逻辑是什么样的?
我曾经阅读过 SDWebImage 的源代码, 就在这里对如何给 UIImageView 加载图片做一个总结吧, SDWebImage 中为 UIView 提供了一个分类叫做 WebCache, 这个分类中有一个最常用的接口,
sd_setImageWithURL:placeholderImage:
, 这个分类同时提供了很多类似的方法, 这些方法最终会调用一个同时具有
progressBlock
completionBlock
的方法, 而在这个类最终被调用的方法首先会检查是否传入了
placeholderImage
以及对应的参数, 并设置
placeholderImage
然后会获取
SDWebImageManager
中的单例调用一个
downloadImageWithURL:...
的方法来获取图片, 而这个 manager 获取图片的过程有大体上分为两部分, 它首先会在
SDWebImageCache
中寻找图片是否有对应的缓存, 它会以 url 作为数据的索引先在内存中寻找是否有对应的缓存, 如果缓存未命中就会在磁盘中利用 MD5 处理过的 key 来继续查询对应的数据, 如果找到了, 就会把磁盘中的缓存备份到内存中.
然而, 假设我们在内存和磁盘缓存中都没有命中, 那么 manager 就会调用它持有的一个
SDWebImageDownloader
对象的方法
downloadImageWithURL:...
来下载图片, 这个方法会在执行的过程中调用另一个方法
addProgressCallback:andCompletedBlock:fotURL:createCallback:
来存储下载过程中和下载完成的回调, 当回调块是第一次添加的时候, 方法会实例化一个
NSMutableURLRequest
SDWebImageDownloaderOperation
, 并将后者加入 downloader 持有的下载队列开始图片的异步下载.
而在图片下载完成之后, 就会在主线程设置 image, 完成整个图像的异步下载和配置.
13. 设计一个简单的图片内存缓存器 (包含移除策略)
待我阅读完 path 开源的
的源代码就来回答.
讲讲你用Instrument优化动画性能的经历
的作用是什么?
This method loads or creates a view and assigns it to the
UIViewController
的实例方法, 我们永远不要直接调用这个方法
[self loadView]
. 这在苹果的
中已经明确的写出了.
会在获取视图控制器的
但是却得到
的具体实现会做下面两件事情中的一件:
如果你的视图控制器关联了一个 storyboard, 那么它就会加载 storyboard 中的视图.
如果试图控制器没有关联的 storyboard, 那么就会创建一个空的视图, 并分配给
如果你需要覆写
你需要创建一个根视图.
创建并初始化
的子视图, 调用
addSubview:
方法将它们添加到父视图上.
如果你使用了自动布局, 提供足够的约束来保证视图的位置.
将根视图分配给
永远不要在这个方法中调用
[super loadView]
viewWillLayoutSubviews
的作用是什么?
viewWillLayoutSubviews
方法会在视图的 bounds 改变时, 视图会调整子视图的位置, 我们可以在视图控制器中覆写这个方法在视图放置子视图前做出改变, 当屏幕的方向改变时, 这个方法会被调用.
17. GCD 里面有哪几种 Queue? 背后的线程模型是什么样的?
GCD 中 Queue 的种类还要看我们怎么进行分类, 如果根据同一时间内处理的操作数分类的话, GCD 中的 Queue 分为两类
Serial Dispatch Queue
Concurrent Dispatch Queue
一类是串行派发队列, 它只使用一个线程, 会等待当前执行的操作结束后才会执行下一个操作, 它按照追加的顺序进行处理. 另一类是并行派发队列, 它同时使用多个线程, 如果当前的线程数足够, 那么就不会等待正在执行的操作, 使用多个线程同时执行多个处理.
另外的一种分类方式如下:
Main Dispatch Queue
Global Dispatch Queue
Custom Dispatch Queue
主线程只有一个, 它是一个串行的进程. 所有追加到 Main Dispatch Queue 中的处理都会在 RunLoop 在执行. Global Dispatch Queue 是所有应用程序都能使用的并行派发队列, 它有 4 个执行优先级 High, Default, Low, Background. 当然我们也可以使用
dispatch_queue_create
创建派发队列.
18. Core Data 或者 sqlite 的读写是分线程的吗? 死锁如何解决?
Core Data 和 sqlite 这两个我还真没深入用过, 我只在小的玩具应用上使用过 Core Data, 但是发现这货实在是太难用了, 我就果断放弃了, sqlite 我也用过, 每次输入 SQL 语句的时候我多想吐槽, 写一些简单的还好, 复杂的就直接 Orz 了. 所以我一般会使用 levelDB 对进行数据的持久存储.
数据库读取操作一般都是多线程的, 在对数据进行读取的时候, 我们要确保当前的状态不会被修改, 所以加锁, 防止由于线程竞争而出现的错误. 在 Core Data 中使用并行的最重要的规则是:
NSManagedObjectContext
必须只从创建它的进程中访问
19. http 的 POST 和 GET 有什么区别?
根据 HTTP 协议的定义 GET 类型的请求是幂等的, 而 POST 请求是有副作用的, 也就是说 GET 用于获取一些资源, 而 POST 用于改变一些资源, 这可能会创建新的资源或更新已有的资源.
POST 请求比 GET 请求更加的安全, 因为你不会把信息添加到 URL 上的查询字符串上. 所以使用 GET 来收集密码或者一些敏感信息并不是什么好主意.
最后, POST 请求比 GET 请求也可以传输更多的信息.
20. 什么是 Binary search tree, 它的时间复杂度是多少?
二叉搜索树是一棵以二叉树来组织的, 它搜索的时间复杂度 $O(h)$ 与树的高度成正比, 最坏的运行时间是 $\Theta(\lg n)$.
已发表评论数()
已收藏到推刊!
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
排版有问题
没有分页内容
视频无法显示
图片无法显示63227人阅读
atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。
& & &&atomic
& & & &&& & & &&设置成员变量的@property属性时,默认为atomic,提供多线程安全。
& & &&& & & &&在多线程环境下,原子操作是必要的,否则有可能引起错误的结果。加了atomic,setter函数会变成下面这样:
& & &&& & & &&& & & &&{lock}
& & &&& & & &&& & & &&& & & &&if
(property != newValue) {&
& & &&& & & &&& & & &&& & & &&&
& & &&[property release];&
& & &&& & & &&& & & &&& & & &&&
& & &&property = [newValue retain];&
& & &&& & & &&& & & &&& & & &&}
& & &&& & & &&& & & &&{unlock}
& & & &&nonatomic
& & & & 禁止多线程,变量保护,提高性能。
& & & &&atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。
& & & &&指出访问器不是原子操作,而默认地,访问器是原子操作。这也就是说,在多线程环境下,解析的访问器提供一个对属性的安全访问,从获取器得到的返回值或者通过设置器设置的值可以一次完成,即便是别的线程也正在对其进行访问。如果你不指定
nonatomic ,在自己管理内存的环境中,解析的访问器保留并自动释放返回的值,如果指定了 nonatomic ,那么访问器只是简单地返回这个值。
& & & &&对基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float, double, char)等等。
& & & &&此标记说明设置器直接进行赋值,这也是默认值。在使用垃圾收集的应用程序中,如果你要一个属性使用assign,且这个类符合NSCopying协& & && & & &&议,你就要明确指出这个标记,而不是简单地使用默认值,否则的话,你将得到一个编译警告。这再次向编译器说明你确实需要赋值,即使它是& && & & &&可拷贝的。
& & & &&对其他NSObject和其子类对参数进行release旧值,再retain新值
& & & &&指定retain会在赋值时唤醒传入值的retain消息。此属性只能用于Objective-C对象类型,而不能用于Core Foundation对象。(原因很明显,retain会增加对象的引用计数,而基本数据类型或者Core
Foundation对象都没有引用计数——译者注)。
注意: 把对象添加到数组中时,引用计数将增加对象的引用次数+1。
& & & &&对NSString 它指出,在赋值时使用传入值的一份拷贝。拷贝工作由copy方法执行,此属性只对那些实行了NSCopying协议的对象类型有效。更深入的讨论,请参考“复制”部分。
copy与retain:
Copy其实是建立了一个相同的对象,而retain不是:
1.比如一个NSString 对象,地址为0×1111 ,内容为@”STR”,Copy
到另外一个NSString 之后,地址为0×2222 ,内容相同。
2.新的对象retain为1&,旧有对象没有变化retain
到另外一个NSString 之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1。
总结:retain 是指针拷贝,copy 是内容拷贝。
assign与retain:
接触过C,那么假设你用malloc分配了一块内存,并且把它的地址赋值给了指针a,后来你希望指针b也共享这块内存,于是你又把a赋值给(assign)了b。此时a和b指向同一块内存,请问当a不再需要这块内存,能否直接释放它?答案是否定的,因为a并不知道b是否还在使用这块内存,如果a释放了,那么b在使用这块内存的时候会引起程序crash掉。
2. 了解到1中assign的问题,那么如何解决?最简单的一个方法就是使用引用计数(reference counting),还是上面的那个例子,我们给那块内存设一个引用计数,当内存被分配并且赋值给a时,引用计数是1。当把a赋值给b时引用计数增加到2。这时如果a不再使用这块内存,它只需要把引用计数减1,表明自己不再拥有这块内存。b不再使用这块内存时也把引用计数减1。当引用计数变为0的时候,代表该内存不再被任何指针所引用,系统可以把它直接释放掉。
总结:上面两点其实就是assign和retain的区别,assign就是直接赋值,从而可能引起1中的问题,当数据为int, float等原生类型时,可以使用assign。retain就如2中所述,使用了引用计数,retain引起引用计数加1,
release引起引用计数减1,当引用计数为0时,dealloc函数被调用,内存被回收。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:388556次
积分:2652
积分:2652
排名:第8189名
原创:18篇
转载:10篇
评论:101条
(1)(1)(1)(4)(6)(2)(1)(4)(8)

我要回帖

更多关于 assign weak的区别 的文章

 

随机推荐