版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
iOS程序员面试分类模拟24简答题1.
id,NSObject,id<NSObject>的区别是什么?正确答案:NSObject修饰的对象肯定是NSObject对象,但id修饰的对象虽然肯定是Ob(江南博哥)jective-C对象,但不一定是NSObject对象,id类型是一种运行时的动态类型,编译器不会对其进行类型检查。id<NSObject>修饰的对象也是一种动态类型对象,对象的类型在运行时才确定,但编译器知道它一定是遵守NSObject协议的。例如:id<NSObject>常用来定义delegate对象。
idfool;
//是Objective-C对象,但不是NSObject对象
NSObject*foo2;
//NSObject对象
id<NSObject>foo3;
//不是NSObject对象,但是遵守NSObject协议
2.
CAAnimation的delegate是强引用还是弱引用?正确答案:CAAnimation的delegate(代理)是强引用,是内存管理中一个罕见的特例。为了避免循环引用问题,delegate通常都使用assign或weak修饰表示弱引用,而CAAnimation动画是异步的,如果动画的代理是弱应用而不是强应用,那么会导致其随时都可能被释放掉。在使用动画时要注意采取措施避免循环引用,例如及时在视图移除之前的合适时机移除动画。
CAAnimation的代理定义如下,明确说明动画的代理在动画对象整个生命周期间是被强引用的,默认为nil。
/*Thedelegateoftheanimation.Thisobjectisretainedforthe
*lifetimeoftheanimationobject.Defaultstonil.Seebelowforthe
*supposeddelegatemethods.*/
@property(nullable,strong)id<CAAnimationDelegate>delegate;
3.
SDWebImage在iOS93DTouch下出现什么问题?正确答案:1)iOS9使用SDWebImage加载图片时,在SDWebImageDownloaderOperation.m文件内有操作可能会在后台线程中更新UI,可能导致意想不到的结果甚至程序崩溃。因此,在想更新UI时一定要保证将UI更新操作同步到主线程。UI更新同步到主线程有3种方法,推荐使用GCD来实现,代码形式如下:
dispatch_async(dispatch_get_main_queue(),^{
/*这里写更新UI操作*/
/*写完UI更新操作要根据需要重新布局layout*/
});
2)iOS9考虑到HTTP的不安全性,系统要求所有的网络请求都使用HTTPS,因此之前的HTTP请求会失效报错,可以通过设置允许继续使用HTTP解决,具体在工程的info.plist配置文件中添加如图所示配置即可(添加AppTransportSecuritySettings配置字段在将其下的AllowArbitaryLoads的值改为YES)。
配置info.plist字段
4.
SDWebImage是什么?加载图片的原理是什么?正确答案:SDWebImage是一个针对图片加载的插件库,提供了一个支持缓存的用于异步加载图片的下载工具,特别为常用的UI元素:UIImageView、UIButton和MKAnnotationView提供了类别扩展,可以作为一个很方便的工具。其中,SDWebImagePrefetcher可以预先下载图片,方便后续使用。
SDWebImage的几点特性:
1)为UIImageView、UIButton和MKAnnotationView进行了类别扩展,添加了Web图片和缓存管理。
2)是一个异步图片下载器。
3)异步的内存+硬盘二级缓冲以及自动的缓冲过期处理。
4)后台图片解压缩功能。
5)可以保证相同的URL(图片的检索key)不会被重复多次下载。
6)可以保证假的无效URL不会不断尝试去加载。
7)保证主线程不会被阻塞。
8)性能高。
9)使用GCD和ARC。
支持的图片格式:
1)UIImage支持的图片格式有JPEG、PNG等,包括GIF都可以被支持。
2)Web图片格式,包括动态的Web图片(使用WebPsubspec)。
使用方法示例:
SDWebImage的使用非常简单,开发中需要的主要就是为一个UIImageView添加在线图片,用到的方法主要就是sd_setImageWithURL方法(新版本方法名都加了sd前缀)。sd_setImageWithURL方法提供了几种重载方法,包括只使用图片URL参数的,以及设置占位图片placeholderImage参数的等,这个方法也是框架封装的最顶层的应用方法,开发中实际主要就用这个方法。以这个方法为入口,可以层层打开往底层看,可以对应到SDWebImage的整个加载逻辑和流程。
/*bjective-C:*/
#import<SDWebImage/UIImageView+WebCache.h>
/*使用SDWebImage框架为UIImageView加载在线图片*/
[imageViewsd_setImageWithURL:[NSURLURLWithString:@"http://www.***.com/***/image.jpg"]
placeholderImage:[UIImageimageNamed:@"placeholder.png"]];
/*Swift:*/
imageView.sd_setImageWithURL(NSURL(string:"http://www.***.com/***/image.jpg"),placeholderImage:UIImage(imageNamed:"placeholder.png"))
SDWebImage加载图片的流程原理:
SDWebImage异步加载图片的使用非常简单,一个方法调用即可完成,但实际上这个方法的调用会使得框架立刻完成一系列的逻辑处理,以最高效的方式加载需要的图片。具体加载流程逻辑如图所示。
SDWebImage异步加载图片流程逻辑图
根据流程可以知道,图片的加载采用了一种二级缓存机制,简单概括意思就是:能从内存缓存直接取就从内存缓存取,内存缓存没有就去硬盘缓存里取,再没有就根据提供的URL到网上下载(下载自然会慢很多),下载的图片还有一个解码的过程,解码后就可以直接用了,另外下载的图片会保存到内存缓存和硬盘缓存,从而下次再取同样的图片就可以直接取了而不用重复下载。
上面的整个流程对应到SDWebImage框架内部,依次会挖掘出下面几个关键方法。最外层的是程序员直接调用的sd_setImageWithURL方法,以此方法为入口依次可能会调用到后面的方法,来完成上面的整个优化加载流程,这里以其中一个入口方法为例:
(1)sd_setImageWithURL
UIImageView(WebCache)的sdsetImageWithURL方法只是个UIView的类扩展接口方法,负责调用并将参数传给UIView(WebCache)的sdintemalSetImageWithWRL方法,参数这里有图片的URL和placeholder占位图片。
(2)sd_internalSetImageWithURL
UIView(WebCache)的sd_internalSetImageWithURL方法先将placeholder占位图片异步显示,然后给SDWebImageManager单例发送loadImageWithURL消息,传给它URL参数让其再给它的SDImageCache对象发送queryCacheOperationForKey消息先从本地搜索缓存图片。
(3)loadImageWithURL
收到loadImageWithURL消息后,SDWebImageManager单例向SDImageCache对象发送queryCacheOperationForKey消息开始在本地搜索缓存图片,SDImageCache对象先对自己发送imageFromMemoryCacheForKey消息从内存中搜索图片缓存,搜到则取出图片并通过SDCacheQueryCompletedBlock回调返回,否则再对自己发送diskImageForKey消息去硬盘搜索图片,搜到则取出图片通过SDCacheQueryCompletedBlock回调返回,内存和硬盘都搜不到则只好重新下载。
(4)downloadImageWithURL
如果本地搜索失败,那么SDWebImageManager会新建一个SDWebImageDownloader下载器,并向下载器发送downloadImageWithURL消息开始下载网络图片;下载成功并解码后一方面将图片缓存到本地,另一方面取出图片进行显示。其中,像图片下载以及图片解码等耗时操作都是异步执行,不会拖慢主线程。
SDImageCache在初始化的时候会注册一些消息通知,在内存警告或退到后台的时候会清理内存图片缓存,应用结束的时候会清理掉过期的图片。
5.
如何理解消息转发机制?正确答案:当一个对象能处理一个消息时,就会执行正常的消息传递步骤。如果一个对象无法处理这个消息,那么就会进入消息转发。默认情况下,如果是以[objectmessage]的方式调用方法,当object无法响应message时,那么编译器会报错。如果是以performSelector的形式来调用,那么编译器在编译时还无法确定类中到底会不会有这个方法的实现。如果没有该方法的实现,那么就会导致程序崩溃。示例代码如下:
/*person类中并不存在eat方法*/
Person*aperson=[[Personalloc]init];
[apersonperformSelector:@selector(eat)];
控制台打印结果如下:
[Personeat]:unrecognizedselectorsenttoinstance0x600000029800
上述这段异常信息实际上是由NSObject的doesNotRecognizeSelector:方法所抛出的,此异常信息表明Person类的实例对象无法响应eat方法。在示例中,消息转发过程以程序的崩溃而结束,但是开发者可以利用runtime,在消息转发过程中采取一些措施,而避免程序的崩溃。当然,先要理解消息转发机制的原理。消息转发机制基本分为3个阶段。
1.动态方法解析
对象在收到无法解读的消息后,将调用其所属类的下列类方法:
+(BOOL)resolveInstanceMethod:(SEL)sel
或者
+(BOOL)resolveClassMethod:(SEL)sel
这两个方法的参数就是那个未知的方法,返回值都是Boolean类型,表示这个类能否动态地添加一个新的方法来处理这条消息。在这里可以新增一个处理该消息的方法。
使用这种方法的前提是:相关的方法的实现代码已经写好,只等着运行期动态插入类的MethodList中就可以了。此方案常用来实现@dynamic属性,示例代码如下:
/*在控制器中调用Person类的实例方法eat,但是eat方法没有实现*/
Person*aperson=[[Personalloc]init];
[apersonperformSelector:@selector(eat)];
/*在Person类中为eat动态添加方法的实现*/
+(BOOL)resolveInstanceMethod:(SEL)sel{
NSString*str=NSStringFromSelector(sel);
if([strisEqualToString:@"eat"]){
IMPimp=method_getImplementation(class_getInstanceMethod(self,@selector(breakfast)));
class_addMethod(self,@selector(eat),imp,"");
}
return[superresolveInstanceMethod:sel];
}
-(void)breakfast{
NSLog(@"我吃了早餐了");
}
程序的打印结果如下所示:
2016-11-0518:25:51.89701[11777:779796]我吃了早餐了
在示例代码中,先将消息转化为字符串,然后检测其是否能够表示eat方法。若是eat方法,则为其设置方法的实现。程序的打印结果表明,已经成功地拦截了消息转发并对未知消息(eat)进行了处理。
2.备用接收者
如果在上一步中无法处理消息,那么当前接收者还有第二次机会来处理未知消息,在这一步,runtime会调用如下方法:
-(id)forwardingTargetForSelector:(SEL)aSelector
方法参数代表未知消息,如果当前接收者能找到备用接收者,那么将其返回;如果找不到,那么就返回nil。通过此方法可以模拟出“多重继承”的一些特性。在一个对象内部,可能还有一系列其他的对象,该对象可通过此方法将能够处理未知消息的相关内部对象返回,这样在外界看来,好像是该对象亲自处理了这些消息。示例代码如下:
/*新建一个PersonHelper类*/
@implementationPersonHelper
@interfacePersonHelper:NSObject
-(void)eat;
@end
-(void)eat{
NSLog(@"别人帮我吃东西");
}
@end
/*在Person.m中设置PersonHelper类的实例为属性*/
@interfacePerson()
@property(nonatomic,strong)PersonHelper*helper;
@end
@implementationPerson
-(instancetype)init{
if(self=[superinit]){
_helper=[[PersonHelperalloc]init];
}
returnself;
}
/*实现forwardingTargetForSelector:方法*/
-(id)forwardingTargetForSelector:(SEL)aSelector{
NSString*str=NSStringFromSelector(aSelector);
if([strisEqualToString:@"eat"]){
return_helper;
}
return[superforwardingTargetForSelector:aSelector];
}
@end
/*在控制器中执行eat方法*/
Person*aperson=[[Personalloc]init];
[apersonperformSelector:@selector(eat)];
以上程序的打印结果如下:
2016-11-0518:45:25.87001[11892:788458]别人帮我吃东西
程序打印结果表明,已经成功地在第二步中将消息转发给其他对象来执行了。这里需要注意,开发者无法操作通过这一步所转发的消息。若是想在发送给备用接收者之前先修改消息内容,那就必须采用完整的消息转发机制来操作。
3.完整的消息转发机制
如果以上两步都无法处理未知消息,那么唯一能做的就是启用完整的消息转发机制。此时会调用如下方法:
-(void)forwardInvocation:(NSInvocation*)anInvocation
这里要创建NSInvocation对象,把与尚未处理的那条消息有关的全部细节都封装于其中。此对象包含选择子、目标及参数。在触发NSInvocation对象时,消息派发系统将消息指派给目标对象。当然,从这个角度看来,这一方法与第二步中的备用接收者的实现效果相等。但是事实上可以在触发消息前,先以某种方式改变消息内容,例如追加另外一个参数,或者改变消息名称等。此外,若发现某个消息不应由本类处理,则应调用父类同名方法,以便继承体系中的每个类都有机会处理此请求。
在使用forwardInvocation:方法前,必须重写以下方法:
-(NSMethodSignature*)methodsignatureForSelector:(SEL)aSelector
消息转发机制使用从这个方法中获取的信息来创建NSInvocation对象。因此,开发者必须重写这个方法,为未知消息提供一个合适的方法签名。示例代码如下:
/*在Person.m中实现完整的消息转发*/
-(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector{
NSMethodSignature*signature=[supermethodSignatureForSelector:aSelector];
if(!signamre&&[_helpermethodSignatureForSelector:aSelector]){
signature=[_helpermethodSignatureForSelector:aSelector];
}
returnsignature;
}
-(void)forwardInvocation:(NSInvocation*)anInvocation{
if([_helperrespondsToSelector:anInvocation.selector]){
[anInvocationinvokeWithTarget:_helper];
}
}
以上程序的打印结果如下:
2016-11-0519:08:13.46501[11951:796216]别人帮我吃东西
默认情况下,NSObject的forwardInvocation:方法实现只是简单调用了doesNotRecognizeSelector:方法,它不会转发任何消息。从某种意义上讲,forwardInvocation:方法类似一个通知中心,可以将所有未知消息都派发出去。通过runtime的消息转发机制,开发者可以为程序动态地增加很多行为,这也是丽试中常考的知识,t量。
6.
如何调试BAD_ACCESS错误?正确答案:调试BAD_ACCESS错误是比较困难的事情,BAD_ACCESS错误是由于访问了野指针,但程序不会在野指针出现时或者在访问野指针的代码处报错,这就导致对其难以察觉。调试BAD_ACCESS错误的思路如下。
1.开启僵尸对象诊断
开启僵尸对象诊断,利用僵尸对象来对野指针的出现位置提供线索。僵尸对象指的是引用计数为0被系统回收的对象,但这些对象暂时还存在内存中,且理论上还是可以使用的,但是不稳定。开启僵尸对象诊断后,僵尸对象会暂时保持活跃用于调试,野指针在对象回收后依然指向该僵尸对象,访问野指针也就是访问僵尸对象的情况下可以被编辑器检测出来。这个时候还是会报BAD_ACCESS错误,但是后台会打印出该线索,例如下面的访问野指针打印的后台信息:
2017-03-1216:28:31.501Debug[2371:1379247]-[TestViewControllerrespondsToSelector:]messagesenttodeallocatedinstance0x16749682
可以看出消息发送给了一个僵尸对象,僵尸对象原本是TestViewController的一个实例,但现在该对象被回收了而开发者还试图访问它,由此可以很容易定位问题所在。
另外,开启僵尸对象诊断的方法为:打开Xcode顶部导航栏的:Product-Scheme-EditScheme,在弹出的界面中选中左侧的Run模式,然后勾选右侧Dianostics下的ZombieObjects。不同版本Xcode可能选项位置略有差异。
2.Analyze(分析)
僵尸对象诊断可以帮助快速定位多数情况下的野指针问题,但有时候不能奏效,这个时候只能利用Xcode的Analyze静态分析帮助检查可能存在问题的地方,而仔细检查问题所在比较费时。
使用方法很简单,选中Xcode项部导航栏Product-Analyze或使用快捷键Command+Shift+B,分析需要花一些时间,然后左侧会列出编辑器发现的存在潜在问题的地方,选中蓝色图标对应的问题项会跳到问题项所在的代码行。但这只能给出一些潜在提示,帮助搜索问题所在,不一定和出现的bug相关。
7.
instancetype和id有什么区别?为什么返回类的实例的类方法或实例方法使用instancetype而不是id?正确答案:instancetype和id都可以用来代表任意类型,将对象类型的确定往后推迟,用于体现Objective-C语言的动态性,使其声明的对象具有运行时的特性。
它们的区别是:instancetype只能作为返回值类型,但在编译期instancetype会进行类型检测,因此对于所有返回类的实例的类方法或实例方法,建议返回值类型全部使用instancetype而不是id;id类型既可以作为返回值类型,也可以作为参数类型,也可以作为变量的类型,但id类型在编译期不会进行类型检测。
8.
MRC中通过调用静态方法创建的新对象,不再使用时需要对其发送release消息吗?正确答案:不需要再发送release消息,因为约定静态方法创建的对象会自动将其放入自动释放池,即已对其发送autorelease消息,所以不可再对其进行手动释放。MRC中静态方法创建新对象的实现模板如下:
/*静态构造方法*/
+(instancetype)personWithName:(NSString*)nameage:(NSInteger)age;
+(instaneetype)personWithName:(NSString*)nameage:(NSInteger)age{
Person*person=[[[Personalloc]init]autorelease];
=name;
person.age=age;
returnperson;
}
9.
什么是数据库三级封锁协议?正确答案:众所周知,基本的封锁类型有两种:排它锁(X锁)和共享锁(S锁)。所谓X锁是事务T对数据A加上X锁时,只允许事务T读取和修改数据A。所谓S锁是事务T对数据A加上S锁时,其他事务只能再对数据A加S锁,而不能加X锁,直到事务T释放数据A上的S锁。若事务T对数据A加了S锁,则事务T就可以对数据A进行读取,但不能进行更新(S锁因此又称为读锁),在事务T释放数据A上的S锁以前,其他事务可以再对数据A加S锁,但不能加X锁,从而可以读取数据A,但不能更新数据A。
在运用X锁和S锁对数据对象加锁时,还需要约定一些规则。例如,何时申请X锁或S锁、持锁时间、何时释放等,这些规则称为封锁协议(LockingProtocol)。对封锁方式规定不同的规则,就形成了各种不同的封锁协议。一般使用三级封锁协议,也称为三级加锁协议。该协议是为了保证正确的调度事务的并发操作。三级加锁协议是事务在对数据库对象加锁、解锁时必须遵守的一种规则。下面分别介绍这三级封锁协议。
(1)一级封锁协议
事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。事务结束包括正常结束(commit)和非正常结束(rollback)。一级封锁协议可以防止丢失修改,并保证事务T是可恢复的,使用一级封锁协议可以解决丢失修改问题。在一级封锁协议中,如果仅仅是读数据不对其进行修改,是不需要加锁的,它不能保证可重复读和不读“脏”数据。
(2)二级封锁协议
一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后方可释放S锁。二级封锁协议除防止了丢失修改,还可以进一步防止读“脏”数据。但在二级封锁协议中,由于读完数据后即可释放S锁,所以它不能保证可重复读。
(3)三级封锁协议
一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。三级封锁协议除防止了丢失修改和不读“脏”数据外,还进一步防止了不可重复读。
10.
类工厂方法是什么?正确答案:简单地说,类工厂方法就是用来快速创建对象的类方法,它可以直接返回一个初始化好的对象。UIKit中最典型的类工厂方法就是UIButton的buttonWithType类工厂方法,开发者使用这个方法指定按钮的类型就可以快速得到一个该类型的初始化好的按钮实例对象。该类工厂方法的定义为:
+(instancetype)buttonWithType:(UIButtonType)buttonType;
使用示例代码如下:
UIButton*customButton=[UIButtonbuttonWithType:UIButtonTypeCustom];
类工厂方法的几个必备特征如下:
1)一定是类方法。
2)返回值一定是id/instancetype类型,因为要返回一个对象。
3)规范的方法名会说明类工厂方法返回的是什么对象,一般是以类名首字母小写开始,例如这里buttonWithType说明返回的是一个button。
11.
类变量的@protected、@private、@public、@package声明各有什么含义?正确答案:前3个跟一般面向对象里面的继承封装概念相同。
@protected:表示变量对子类可见,而对于其他类来说变量是私有的,不可访问。
@private:表示变量完全私有化,只对本类可见,其子类也不可访问。
@public:公开变量,表示变量对所有类都是开放可见的,都可以访问。
最后一个@package是Objective-C中特有的一个修饰词,一般在开发静态类库的时候会用到,意思是这个关键词修饰的变量对于framework包内部来说是@protected类型的,而对于包外来说是@priviate类型的,这样可以实现包内变量的封装,包内可以使用而包外不可用,防止使用该包的人看到这些变量。
12.
网络图片处理问题中怎么解决一个相同的网络地址重复请求的问题?正确答案:可以通过建立一个以图片下载地址为key,以下载操作为value的字典,图片地址是唯一的,可以保证key值唯一。当需要加载该图片时,先根据key值去本地缓存中找,看该图片是否已经下载,如果key值匹配,那么直接从本地取图片资源从而避免重复下载操作,如果本地找不到,那么需要根据key值中的网络图片地址重新去网络上下载。
13.
内连接与外连接有什么区别?正确答案:内连接,也称为自然连接,只有两个表相匹配的行才能在结果集中出现。返回的结果集是两个表中所有相匹配的数据,而舍弃不匹配的数据。由于内连接是从结果表中删除与其他连接表中没有匹配行的所有行,所以内连接可能会造成信息的丢失。内连接的语法如下:
selectfieidlistfromtablel[inner]jointable2ontable1.column=table.column
内连接是保证两个表中所有的行都要满足连接条件,而外连接则不然。与内连接不同,外连接不仅包含符合连接条件的行,还包括左表(左外连接时)、右表(右外连接时)或两个边接表(全外连接)中的所有数据行。也就是说,只限制其中一个表的行,而不限制另一个表的行。SQL的外连接共有3种类型:左外连接(关键字为LEFTOUTERJOIN)、右外连接(关键字为RIGHTOUTERJOIN)和全外连接(关键字为FULLOUTERJOIN)。外连接的用法和内连接一样,只是将INNERJOIN关键字替换为相应的外连接关键字。
内连接只显示符合连接条件的记录,外连接除了显示符合连接条件的记录外,还显示不符合连接条件的记录。例如,若用左外连接,还显示左表中记录。
例如,有两个学生表A(见表1)和课程表B(见表2)。表1学生表A学号姓名0001张三0002李四0003王五表2课程表B学号课程名0001数学0002英语0003数学0004计算机对表1和表2进行内连接后的结果见表3。表3内连接结果学号姓名课程名0001张三数学0002李四英语0003王五数学对表1和表2进行右外连接后结果见表4。表4右外连接结果学号姓名课程名0001张三数学0002李四英语0003王五数学0004
计算机
14.
如何使用GCD实现线程之间的通信?正确答案:在iOS应用程序的开发中,一般需要在主线程中进行UI刷新。例如,响应单击、滚动或者拖曳等事件,所以主线程一般也被称为UI线程。在主线程中,应该尽量避免在主线程中执行一些耗时的操作,如文件的上传和下载等。应该将这些耗时操作放到子线程中执行,等子线程的耗时操作执行完成后,再通知主线程更新相应的UI。要完成这样的操作,就必须实现线程之间的通信,GCD是实现线程之间通信的常用方式。示例代码如下:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
/*执行耗时操作*/
for(inti=0;i<10000;i++){
NSLog(@"i=%i",i);
}
/*回到主线程*/
dispatch_async(dispatch_get_main_queue(),^{
//更新UI
}):
});
先将需要执行的耗时操作放入全局并发队列中,再使用dispatch_async异步函数执行并发队列,这样就会开启新的线程执行耗时操作,不会阻塞主线程的任务。当耗时任务完成后,通过主队列回到主线程执行相应的UI更新操作。需要强调的是,当使用主队列时,无论是使用dispatch_async异步函数,还是使用dispatch_sync同步函数,执行的结果是一样的。因为主队列是一种特殊的串行队列,在主队列中任务总会在主线程中执行。
15.
使用dealloc方法释放对象时,为什么一定要调用[superdealloc]方法?在何处调用?正确答案:因为子类的很多实例变量是继承自父类的,所以要调用[superdealloc]方法来释放从父类继承来的实例变量,实际上还是释放自己的实例变量,只是继承来的这部分只能调用父类的dealloc方法来释放。
按照自下往上的逻辑,一般要先释放子类的实例,然后释放父类的实例。自下往上的原因是,在调用[superdealloc]方法之前如果不先把子类中的变量从内存中释放掉,容易造成子类中变量的内存积压,导致内存泄漏,所以[superdealloc]方法应该在释放掉子类变量之后最后调用。当然在ARC中就不需要考虑这些问题了,变量会自动释放,此方法也不存在了。
16.
整型值和浮点值在赋值操作中如何相互转换?正确答案:在Objective-C的数值运算中,表达式中的整型值和浮点值遵循一种隐式转换的规则。实例代码如下:
floatf1=3.141592,f2;
inti1,i2=3;
/*浮点数转换为整型*/
i1=f1;
NSLog("f1=%f,i1=%i",f1,i1);
/*整型数转换为浮点型*/
f2=i2;
NSLog("f2=%f,i2=%i",f2,i2);
以上代码段输出的结果是:
f1=3.141592,i1=3
f2=3.000000,i2=3
其执行的过程遵循以下规则:
1)在Objective-C中,只要将浮点值赋值给整型变量,数字的小数部分都会被删除。因此在程序中,将f1的值指派给i1时,数据3.141592的小数部分将被删除,这就意味着数据中只有整数的那一部分(即3)被存储到了i1中。程序的第一行输出结果就验证了这种情况。
2)把整型变量的值指派给浮点变量的操作不会引起数值的任何改变,数值仅仅由系统自动转换并存储到浮点变量中。因此,当把整型变量i2的值指派给浮点型变量f2时,i2的值(即3)由系统进行了正确的转换并存储到f2中。程序的第二行输出结果就验证了这种情况。
17.
UIView和CALayer的区别与联系是什么?正确答案:1.UIView和CALayer是什么?
CALayer是动画中经常使用的一个类,它包含在QuanzCore框架中。CALayer类在概念上和UIView类似,同样是一些被层级关系树管理的矩形块,也可以包含一些内容(像图片、文本或者背景色),管理子图层的位置。它们有一些方法和属性用来做动画和变换。使用CoreAnimation开发动画的本质就是将CALayer中的内容转化为位图供硬件操作。
CALayer是一个比UIView更底层的图形类,是对底层图形API(OpenGLES)一层层封装后得到的一个类,用于展示一些可见的图形元素,保留了一些基本的图形化操作,但同时由于相对高度的封装,使得操作使用变得很简单。CALayer用于管理图形元素,甚至可以制作动画,它保留了一些几何属性,如位置、尺寸、图形变换等。一般的CALaver是作为UIView背后的支持角色,在创建了一个UIViewr的同时也存在一个相应的CALayer。UIView作为CALayer的代理角色去实现一些功能,例如常见的为UIView制作一个圆角,就会用到UIView背后的layer操作:
view.layer.cornerRadius=10;
CALayer可以通过UIView很方便地展示操作UI元素,但是CALayer自身单独也可以展示和操作可见元素,且灵活度更高,它自身有一些可见可设置的属性,如背景色、边框、阴影等。
另外,UIView简单来说是一个可以在里面渲染可见内容的矩形框,它里面的内容可以和用户进行交互,UIView可以对交互事件进行处理。除了其背后CALayer的图形操作支持,UIView自身也有像设置背景色等最基本的属性设置。
2.UIView和CALayer的联系
UIView和CALayer的主要联系上面已经提到,CALayer在UIView背后提供更加丰富灵活的图形操作,UIView作为CALayer的代理更加快速地帮CALayer显示一些常用的UI元素并提供交互。
另外,UIView类是所有视图的基类,CALayer是图层类。事实上,UIView和CAlayer是平行的层级关系。每一个UIView都有一个CALayer实例的图层属性,视图的责任就是创建并管理图层,以确保当子视图在层级关系中被添加或者被移除的时候,与它们相关联的图层也同样在层级关系树中有相同的操作。
3.UIView和CALayer的区别
1)CALayer无法响应用户事件。UIView和CALayer的最明显区别在于它们的可交互性,即UIViewr可以响应用户事件,而CALayer不可以,原因可以从这两个类的继承关系上看出(见图)。UIView是继承自UIResponder的,决定了UIView类及其子类能够通过响应链(iOS通过视图层级关系来传递触摸事件)接收并响应用户事件。而CALayer直接继承于NSObject类,所以它不清楚具体的响应链,也就无法响应用户事件。
CALayer和UIView继承关系
2)分工不同。UIView类侧重于对显示内容的管理和整体布局,而CALayer侧重于显示内容的绘制、显示和动画。
3)所属框架不同。UIView类是属于UIKit.framework框架的,UIKit框架主要就是用来构建用户界面的。CALayer类是属于QuartzCore.framework框架的,而且CALayer是作为一个低级的,可以承载绘制内容的底层对象出现在该框架的。
18.
如何使用runtime动态添加一个类?正确答案:runtime之所以非常强大,很关键的一点就是它能够动态地创建一个全新的类或对象。在runtime.h文件中可以查到动态创建一个类所涉及的所有函数。
/*创建一个新类或元类*/
objc_allocateClassPair(Classsuperclass,constchar*name,size_textraBytes)
/*注册一个通过objc_allocateClassPair方法创建的类*/
objc_registerClassPair(Classcls)
/*销毁一个类及其元类*/
objc_disposeClassPair(Classcls)
上面3个函数的作用见表。动态创建类所涉及的3个函数函数名作用objc_allocateClassPair函数它的作用是创建一个新类或元类。如果开发者想让这个类成为基类,那么参数superclass指定为nil。参数extraBytes是分配给类和元类对象尾部的索引ivars的字节数,通常指定为0objc_registerClassPair函数当创建完新类后,需要调用这个方法来注册这个类,之后这个类才可以在程序中使用objc_disposeClassPair函数用于销毁一个类及其元类。需要注意的一点是,如果程序运行中还存在类或其子类的实例,那么就不能调用该方法
那么,如何运用上述3个函数动态地添加一个类呢?示例代码如下:
/*创建一个新类myClass*/
ClassmyClass=objc_allocateClassPair([NSObjectclass],"myClass",0);
/*添加ivar*/
//@encode(aType):返回该类型的C字符串
class_addIvar(myClass,"_address",sizeof(NSString*),log2(sizeof(NSString*)),@encode(NSString*));
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 基于构造性覆盖算法的中文文本分类:模型构建与效果优化
- 基于机器视觉的BGA集成电路精密视觉定位系统及图像处理技术探究
- 基于本体论活动学习与ANN融合构建个体居民行为模型的探索
- 基于本体和描述逻辑的SWRL推理:原理、应用与优化
- 基于有限元法的搅拌车主副车架结构拓扑优化:理论、实践与创新
- 基于有限元与实验双维度的数控车床主轴热特性剖析与精准调控策略研究
- 基于智能终端与分布式账本技术的预付费卡系统构建:设计理念、技术实现与应用探索
- 基于智能技术的某型电动舵机自动检测系统深度解析与创新设计
- 基于智能优化极限学习机的城市污水处理厂水质精准预测与深度分析
- 基于时间自动机建模的BGA焊球高度实时检测系统的创新与实践
- 2026年专业技术人员继续教育公需科目-智慧城市历年参考题库含答案解析
- 2026年县直机关干部公开遴选笔试试卷(附答案)
- 26新六年级上册道德与法治【知识点总结】
- 石材护理技术规范SOP
- CSCO结直肠癌诊疗指南(2026版)
- 《新能源专业导论》新能源相关专业全套教学课件
- 教科版小学科学二年级上册和下册【全册】教学课件上下共两册
- 人力资源业务开展制度
- 中华传统文化课程思政教学案例
- 18.2 课时1 勾股定理的逆定理 教学课件 2025-2026学年沪科版数学八年级下册
- 2026年英语流利说的测试题及答案
评论
0/150
提交评论