《iOS知识点梳理-ObjectC语言》

知识点总结中,如有幸被您观看,更有可能看到不足,期待指出交流

前言

这个是高手,这个是高手,这个是高手

方法和选择器的不同
  • selector 是一个方法的名字,method是一个组合体,包含了名字和实现
core foundation的内存管理
  • 凡是带有create, copy, retain 等字眼的函数,创建出来的对象, 都需要在最后做一次release
  • 比如 CFRunLoopObserverCreate release函数: CFRelease(对象)
malloc和new的区别
  • new 是c++的操作符, malloc是c中的一个函数
  • new 不止是是分配内存,而且会调用类的构造函数,同理delete会调用类的析构函数,而malloc则只分配内存,不会进行初始化类成员的工作,同样free也不会调用析构函数
  • new可以认为是malloc加构函数的执行
  • new 出来的指针是直接带类型信息的
OC中的反射机制
  • class反射
  • 通过类名的字符串形式实例化对象
Class class  NSClassFromString@(@"student");
student *stu = [[class alloc] init];
  • 将类名变成字符串
Class class = [Student class];
NSString *className = NSStringFromClass(class);
  • SEL的反射
  • 通过方法的支付创新是实例化方法
    SEL selector = NSSelectorFromClass(@"setName");
    [stu performSelector:selector withObject:@"Mike"];
  • 将方法变成字符串
    NSStringFromSelector(@selector(*setName:))
SEL 理解和调用

理解:

  • SEL 就是对方法的一种包装.包装的SEL类型数据它对应相应方法地址,找到方法地址就可以调用方法.在内存中每个类的方法都储存在类对象中,每个方法都有一个与之对应的SEL类型数据,根据一个SEL数据就可一个找到对应的方法地址,进而调用方法
  • SEL s1 = @selector(tet1); // 将test1方法包装成SEL对象
  • SEL s2 = NSSelectorFromString(@"test1"); // 将一个字符串方法转换成SEL对象

调用:

  • 直接通过方法名来调用
  • 间接的通过SEL数据来调用 SEL aaa = @selector(text);[person performSelector:aaa];
协议中是什么意思?子类继承了父业,那么子类会遵守父类中遵守的协议吗?协议中能够定义成员变量?如何约束一个对象类型的变量要存储的地址是一个遵守一个协议对象?
  • 遵守NSObject协议
  • 能,但是只在头文件中声明,编译器是不会自动生成实例变量的.需要自己处理getter和setter方法
  • id
NS/CF/CG/CA/UI 这些前缀的含义
  • 函数归属于 cocoa Fundation 框架
  • 函数归属于 core Fundation 框架
  • 函数归属于 coreGrahics.frameWorks 框架
  • 函数归属于 UIKit 框架
面向对象都有哪些特征以及你对这些特征的理解
  • 继承:继承是从已有类得到继承信息创建新类的过程.提供继承信息的类被成为父类(超类,基类);得到继承信息的类被成为子类(派生类).继承让变化中的软件系统有一定的延续性,同时继承也是封装程序中可变因素的重要手段
  • 封装:封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口.我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装.可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口
  • 多态性:多态性是指允许不同子类型的对象对统一消息做出不同的响应.简单的说就是用同样的对象调用同样的方法但是做了不同的事情.多态性分为编译时的多态性和运行时的多态性.方法重载(overload)实现的是编译时的多态性(也成为前绑定),而方法重写(override)实现的是运行时的多态性(也称后绑定).运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:1.方法重写(子类继承父类并重写父类中已有的或抽象的方法);2.对象造型(用父类型引用引用子类对象,这样同样的引用调用同样的方法就会根据子类对象和不同而表现出不同的行为)
  • 抽象:抽象是将一类对象的共同点特征总结出来构造类的过程,包括数据抽象和行为抽象两方面.抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么.
Object-C,动态运行时语言
  • 主要是将数据类型的确定由编译时,推迟到运行时.这个问题其实浅涉及到两个概念,运行时和多态
  • 简单的来说,运行时机使我们直到运行时才去确定一个对象的类别,以及调用该类别对象指定方法.
  • 多态:不同对象以自己的方式响应相同的消息的能力叫多态
    -意思就是建设生物类(list)都用用一个相同的方法-eat,人类属于生物,猪也属于生物,都继承了list后,实现各自的-eat,但是调用使我们只需要调用各自的eat方法.也就是不同的对象都以自己的方式响应了相同的消息(响应了eat这个选择器).因此也可以说,运行时机制是多态的基础.
readwrite,readonly,assign,retain,copy,nonatomic属性的作用?
  • readwrite 是可读可写特性,需要生成getter防范和setter方法
  • readonly 是只读特性 只会生成getter方法, 不会生成setter方法,不希望属性在类外改变
  • assign 是赋值特性, setter 方法将传入参数赋值给实例变量;仅设置变量时,assign用于简单数据类型,如NSInteger,double,bool;
  • retain 表示持有特性,setter方法将传入参数先保留,再赋值,传入参数的引用计数retaincount会+1
  • copy 便是赋值特性,setter方法会传入对象复制一份;需要完全一份新的变量时;
  • nonatomic 非原子性操作,确定编译器生成的seter getter 是否需要要原子操作;
  • atomic 表示多线程安全, 一般使用 nonatiomic;
NotificationCenter,kvc,kvo,Delegate,区别
  • KVO(Key-Value-Observing):一对多,观察者模式,键值观察机制,他提供了观察某一属性变化的方法,极大简化了代码
  • KVC(Key-Value-Coding):是键值编码,一个对象在调用setValue
    -- 检查是否存在相应key的set方法,车载就调用set方法
    -- set方法不存在的,就查找_key的成员变量是否存在,存在就直接赋值
    -- 如果_key没有找到,就查找相同名称的key,存在就赋值
    -- 如果没有就调用valueForUndefinedkey和setValue:forUndefinedKey.
  • Delegate:通常发送者和接受者的关系是直接的一对一关系
    -- 代理的目的是改变或者传递控制链.允许一个类在某些特定时刻通知到其他类,而不需要要获取到那些类的指针.
    -- 可以减少框架复杂度.消息的发送者告知接收者某个事件将要发生,delegate同意然后发送响应事件,delegate机制使得接受者可以改变发送者的行为
  • Notification:观察者模式,通常发送者和接受者的关系是间接的多对多关系.消息的发送者告知接受者事件已经发生或者将要发送,仅此而已,接收者并不能反过来影响发送者的行为
  • 区别
    -- 效率肯定是delegate比NSNotification高.
    -- delegate方法比notification更加直接,需要关注返回值,所以delegate方法往往包含should这个很传神的词.相反的,notification最大的特色就是不关心结果.所以notification往往用did这个词汇.
    -- 俩个模块之间联系不是很紧密,就用notificaiton传值,例如多线程之间传值用notification.
    -- delegate 只是一种较为简单的回调,而且主要用在一个模块当中,例如底层功能完成了,需要把一些值传到上层去,就事先吧上层的函数通过delegate传到底层,然后在底层call这个delegate,它们都在一个模块中,完成一个功能,例如说 NavgationController 从 B 界面 到 A 点返回按钮(调用popViewController方法)可以用delegate比较好
懒加载
  • 懒加载,只在用到的时候才回去初始化.也可以理解成延时加载.我觉得最好也最简单的一个例子就是tableView中图片的加载显示了,一个延时加载,避免内存过高,一个异步加载,避免线程堵塞提高用户体验
OC有多继承吗,没有的话可以用什么方法代替
  • 多继承即一个子类可以有多个父类,它继承了多个父类的特性
  • Object-C的类没有多继承,只有支持单继承,如果要实现多继承的话,可以通过类别和协议的方式来实现
  • protocol(协议)可以实现多个接口,通过实现多个接口可以完成多继承:
  • Category(类别)一般使用分类,用Category去重写类的方法,仅对本Category有效,不会影响到其他类与原有类的关系
分别描述类别(categories)和延展(extensions)是什么?以及俩者的区别?继承和类别在实现中有何区别?为什么category只能为对象添加方法,却不能添加成员变量
  • 类别:在没有原类.m文件的基础上,给该类添加方法;
  • 延展: 一种特殊的类别,主要在一个类的.m文件里声明和实现延展的作用,就是给某个类添加私有方法和私有变量.
    ** 俩个的区别: **
    -延展可以添加属性并且他添加的方法是必须要实现的.延展可以认为是一个私有的类目
    -类别可以再不知道,不改变原来代码的情况下往里面添加新的方法,只能添加,不能删除
  • 并且如果类别和原来类中的方法产生名称冲突,那么类别会覆盖之前的防范,类别具有更高的优先级
  • 集成可以增加,修改删除方法,添加属性
  • category 只能为对象添加方法,却不能天啊及成员变量的原因:如果可以添加成员变量,添加的成员变量没有办法初始化
Object-C有是有方法吗?私有变量呢?如果没有的话,有没有什么代替的方法?
  • Objective-c类里面的方法只有俩种,静态方法和实例方法,但是可以通过把方法的声明和定义都放在.m文件中.在Objective-C中,所有实例变量默认都是私有的,所有实例方法默认都是公有的
include和#import的区别?#import与@class的区别
  • import 指令是 Object-C针对 #include 的改进版本, #import 确保引用的文件只会被引用一次,这样这不会陷入递归包含的问题了
  • import 与 @calss 二者的区别在于
    -- import 会链入该头文件的全部信息,包括实例变量和方法等;而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑
    -- 在头文件中一般使用@class来声明这个名称是类的名称,不需要知道其内部的实体变量和方法
    -- 在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要用#import来包含这个被引用类的头文件
    -- 在编译效率方面, 如果你有100个头文件都#import了同一个文件,或者这些文件是依次应用的,如A->B,B->C,C->D,这样的引用关系,如果你的类有很多的话,这将会耗费大量的时间.而@class则不会
    -- 如果有循环依赖关系,如A->B,B->A,这样的相互依赖关系,如果使用#import来相互包含,那么就会出现编译错误,如果使用@class在俩个类的头文件中相互声明,则不会有变异错误的出现.
浅拷贝和深拷贝
  • 浅拷贝:只赋值指向对象的指针,而不复制引用对象本身.
  • 深复制:复制引用对象本身.深复制就好理解理解了,内存中存在了两份独立对象本身,当修改A时,A_copy不变.
类变量的@protected,@private,@public,@package声明有什么含义?

变量的作用域不同

  • @protected 该类和子类中访问,是默认的
  • @private 只能在本类中访问;
  • @public 任何地方都能访问
  • @package 本包内使用,跨包不能使用
Objective-C和C,C++之间的联系和区别
  • Objective-C和C++都是C的面向对象的超集
  • Object与C++的区别主要点:Object_C是完全动态的,支持在运行时动态类型决议,动态绑定以及动态转载;而C++是部分动态的,编译时静态绑定,通过嵌入类(多重集成)和虚函数(虚表)来模拟实现
  • Objective-C在语言层次上辞职动态消息转发,其消息发送语法为[object function];而且C++ 为 objec->function(),两者的语义也不同,在Objective-C里是发送消息到一个对象上,至于这个对象能不能响应消息以及是响应还是转发消息都不会crash;而在C++里是说对象进行了某个操作,如果对象没有这个操作的话,要么编译会报错(静态绑定),要么程序会crash掉的 (动态绑定).
目标-动作机制
  • 目标是动作消息的接收者,一个控件,或者更为常见的是他的单元,以插座变量的形式保持其动作消息的目标.
  • 动作是控件发送给目标的消息,或者从目标的角度看,它是目标为了响应动作而实现的方法.程序需要某些机制来进行事件和指令的翻译.这个机制就是目标-动作机制.
Objective-C优点和缺点
  • 优点:1.Cateogiey.2.posing.3动态识别4.指标计算;5.弹性信息传递;6.不是一个过度复杂的C衍生语言;7.Objective-C与C++可混合编程
  • 确定:1.不支持命名空间;2.不支持运算符重载;3.不支持多重继承;4使用动态运行类型,所有的方法都是函数调用,所以很多编译时优化方法都用不到.(如内联函数等),性能低劣
C语言的函数调用和OC的消息机制有什么区别
  • 对于C语言.函数的调用在编译的时候会决定调用哪个函数.编译完成之后直接顺序执行
  • OC的函数调用成为消息发送.属于动态调用过程.在编译的时候并不能解决真正的调用哪个函数(事实证明在编译阶段,OC可以调用任何函数,即使这个函数并未实现,只要申请过就不会报错,而C语言在编译阶段就会报错).只有在真正运行的时候才会根据函数的名称找到对应的函数来调用.
什么是谓词

谓词就是通过NSPredicate给定的逻辑条件作为约束条件,完成对数据的筛选

// 定义谓词对象,谓词对象中包含了过滤条件
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age<%d", 30];
// 可以使用&&进行多条件过滤
predicate= [NSPredicate preicateWithFormat:@"name='1'&&age > 40"];
array = [persons filteredArrayUsingPredicate:predicate];
// 包含语句的使用
predicate = [NSPredcate predicateWithFormat:@"self.nameIN{'1','2','3'}||sele.age IN{30,40}"]
/** 指定字符开头和指定字符结尾,是否包含指定字符 */ 
// name已a开头的
predicate = [NSPredicate predicateWithFormat:@"name BEGINSWITH'a'"];
// name 中包含字符a的
predicate = [NSPredicate redicateWithFormat:@"name Contains'a'"];
// like 进行匹配多个字符
predicate = [NSPredicate predicateWithFormat:@"name like 's'"];
// ?代表一个字符,下面的查询条件是:name中第二个字符是s的
predicate = [NSPredicate predicateWithFormat:@"name like '?s'"];

C与OC混用

  • 处理.m可以识别C和OC,.mm可以识别c c++ oc 但是cpp只能用c/c++
atomic和nonatomic的区别
  • atomic提供多线程安全,房子读写未完成的时候被另外一个线程读写,造成数据错误
  • nonatomic在管理内存的环境中,解析的访问器保留并自动释放返回值,若指定了nonatomic,那么访问器只是简单的返回这个值
常见的oc数据类型那些,和c的基本类型有啥区别
  • 常见的:NSInteger CGFloat NSString NSNumber NSArray NSDate
  • NSInteger 根据32或者64位系统确定本身是int还是long
  • CGFloat根据32或者64位系统确定本身是float还是double
  • NSString NSNumber NSArray NSDate 都是指针类型的对象,在堆中分配内存,c语言中char int 等都是在栈中分配空间
id 和 nil 代表什么
  • id 类型的指针可以指向任何OC对象
  • nil 代表空值(空指针的值, 0)
nil和NULL的区别
  • 从oc的官方语法上面看,nil标识对象的指针即对象的引用为空
  • null表示指向基础数据类型变量即c语言变量的指针为空
  • 在非arc中 俩个空可以互换,但是在arc中普通指针和对象引用被严格限制,不能互换
    nil,Nil,NULL和NSNull区别
  • nil和C语言的NULL相同,在objc/objc.h中定义.nil表示objective-C对象的值为空.在C语言中,指针的空值用NULL表示.在Objective-C中,nil对象调用任何方法表示什么也不执行,也不会崩溃
  • Nil:那么对于我们Objective-C开发来说,Nil也就代表((void*)0).但是它是用来代表空类的,比如:Class myClass = Nil;
  • NULL:在C语言中,NULL是无类型的,只是一个宏,它代表空.这就是在C/C++中的空指针.对于我们Objective-C开发来说,NULL就表示((void*)0)
  • NSNull:NSNull集成于NSObject的类型.它是很特殊的类,它表示是空,什么也不是储存,但是它确是对象,只是一个占位对象.使用场景就不一样了.比如说服务端接口中让我们在值为空的时,穿空.NSDictionry *parameter = @{@"arg1":@"value1",@"arg2",arg2.isEmpty?[NSNull null]:arg2};
    *NULL,nil,Nil这三者对于Objective-C中值是一样的,都是(void )0,那么为什么要区分,又与NSNull之间有什么区别
  • NULL 是宏, 是对于C语言指针来使用的,表示空指针
  • nil 是宏, 是对于Objective-C中的类而使用的,表示类指向空
  • Nil 是宏,是对于Objective-C中的类而使用的,表示类指向空
  • NSNull 是类类型, 是用于表示空的占位对象,与JS或者服务端的null类似的含义
像一个nil对象发送消息会发生什么?
  • 像nil发送消息是完全有效的--只是在运行的时候不会有任何的作用
  • 如果一个方法返回值是一个对象,那么发送给nil的消息将返回0(nil)
  • 如果方法返回值为指针类型,其指针大小为小于或者等于sizeof(void*),float,double,long double 或者 longlong的整型标量, 发送给nil的消息将返回0(nil)
  • 如果方法返回值为指针类型,其指针大小为小于或者等于sizeof(void*),float,double,long double或者long long 的整型标量, 发送给nil的消息将返回0
    如果方法返回值为结构体,正如在《Mac OS X ABI 函数调用指南》,发送给nil的消息将返回0,结构体中各个字段的值都是0.其他的结构体数据类型将不是用0填充的
  • 如果方法的返回值不是上述提到的几种情况,那么发送给nil的消息的返回值将是未定义.self.和self->的区别
  • self.是调用get或者set方法
  • self是当前本身, 是一个指向当前对象的指针
  • self->是直接访问成员变量
类方法和实例方法的本质区别和联系
《iOS知识点梳理-ObjectC语言》_第1张图片
屏幕快照 2018-12-14 下午5.37.31.png
_block/weak修饰符区别
  • _block在arc和mrc环境下都能使用,可以修饰对象,也能修饰基本数据类型
  • _weak只能在arc环境下使用,只能修饰对象(NSString),不能修饰基本数据
  • _block对象可以在block中重新赋值, _weak不行
写一个NSString类的实现
NSString *str = [[NSString alloc]initWithCString:nullTerminatedCString encodeing:encoding];
为什么标准头文件都有类似以下的结构
ifndef __INCvx Worksh
define __INCvx Worksh
ifdef __cplusplus
ectern "C"{
endif
ifdef __cplusplus
}
endif
endif

显然,头文件中的编译宏#ifndef INCvxWorksh,#define INCvxWorksh,#endif 的作用是防止该头文件呗重复引用

init和intwithobject区别(语法)
  • 后者给属性赋值
@property的本质是什么?ibar,getter,setter是如何生成并添加到这个类中的

@property的本质:
@property = ivar(实例变量) + getter (取方法) + setter(存方法)
属性(peoperty)两大概念:
ivar(实例变量),存取方法(access method = getter + setter)
ivar,getter,setter如何生成并添加到类中:
这是编译器自动合成的,通过@synthesize关键字指定,若不指定,默认为这是编译器自动合成的,通过@synthesize关键字指定,若不指定,默认为@shnthesize propertyName = _propertyName;若手动实现了getter/setter方法,则不会自动合成.
现在编译器已经默认为我们添加@synthesize propertyName = propertyName;因此不再需要手动添加,除非你真的要改变成员变量
生成getter方法时,会判断当前属性名是否有
,比如声明属性@property(nonatiomic,copy) NSString *_name; 那么所生成的成员变量就会变成name,如果我们要手动生成getter方法,就要判断是否以开头了.不过,命名都要有规范,是不允许色林属性是使用开头的,不规范的命名,在使用runtime的时候,会带来很多不方便

这个写法会出什么问题:@property(copy)NSMutableArray *array;
  • 没有指明未nonatiomic,因此就是atomic原子操作,会影响性能.该属性使用同步锁,会在创建时生成一些额外的代码用于帮助编写多线程程序,这会带来性能问题,通过声明nonatomic可以节省这些虽然很小但是不必要的额外开销.在我们的应用程序中,几乎都是使用nonatiomic来声明的,因为使用atomic并不能保证绝对的线程安全,对于要绝对保证线程安全的操作,还需要使用更高级的方式来处理,比如NSSpinLock,@syncronized等
  • 因为使用的是 copy,所得到的实际是NSArray类型,它是不可变的,若在使用中使用了增,删,改操作,就会crash
@protocol和category中如何使用@property
  • 在protocol中使用@property只会生成setter和getter方法声明,我们使用属性的目的是希望遵守我协议的对象能实现该属性
  • category 使用@property也只是会生成stter和getter方法的声明,如果我们真的需要给category增加属性的实现,需要借助于运行时的两个函数
    -- objc_setAssociatedObject
    -- objc_getAssociatedObject
@property中有哪些属性关键字
  • 原子性(atomic, nonationmic)
  • 读写(readwrite, redonly)
  • 内存管理(assign,strong,weak,unsafe_unretaied,copy)
  • getter, setter
isa指针问题
  • isa: 是一个Calss类型的指针,每个是你对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针,指向meteCalss(元类).元类保存了类方法的李彪.当类方法被调用时,先会从本身查找类方法的实现,如果没有,元类会先从他父类查找该方法.同时注意的是:元类(meteCalss)也是类,它也是对象.元类也有isa指针,它的isa指针最终指向一个根元类(root meteClass).根元类的isa指向本身,这样就行程了一个封闭的内循环
如何访问并修改一个类的私有属性
  • 一种是通过KVC获取
  • 通过runtime访问并修改私有属性
如何为Class定义一个对外只读对内可读写的属性

在头文件中将属性定义为readonly,在.m文件中将属性新重新定义readwrite

Objective-C中,meta-Class指的什么?

meta-class是Class对象的类,为这个Class类储存类方法,当一个类发送消息时,就会去这个类对应的metaClass中查找那个消息,每个Class都有不同的meta-class,所有的meta-class都使用基类的meta-class(假如类继承NSObject,那么他对应的meta-class也是NSObject)作为他们的类

Objective-C的class是如何实现的,selector是如何转换成C语言的函数调用的
  • 当一个类被正确的编译过后,在这个编译成功的类里面,存在一个变量用于保存这个类的信息.我们可以通过[NSClassFromString]或[obj class].这样的机制允许我们在程序执行的过程当中,可以Class来得到对象的类,也可以在程序执行的阶段动态的生成一个再编译阶段无法确定的一个对象.(isa指针)
  • @selector()基本可以等同C语言的中函数指针,只不过C语言中,可以把函数名直接赋给一个函数指针,而Object-C的类不能直接应用函数指针,这样只能做一个@selector语言来取.
@interface foo
- (int)add:int val;
@end

SEL class_func; //定义一个类方法指针
class_func = @selector(add:int);
  • @selector 是查找当前类的方法, 而[object @selector(方法名:方法参数...)];是取object对应类的相应方法
  • 查询类方法时,除了方法名,方法参数也查询条件之一
  • 可以用字符串来找方法 SEL 变量名 = NSSelectorFromString(方法名字的字符串);
  • 可以运行中用SEL变量反向查出方法名字字符串.NSString *变量名 = NSStringFromSelect(SEL参数)
  • 取到Selector的值以后,执行seletor.SEL变量执行.用performSelecor方法来执行.[对象 performSelector:SEL变量 withObjet:参数1 withObject:参数2];
对于语言NSString *obj = [[NSData alloc] init]; 编译时和运行时 obj 分别是什么类型
  • 编译时是NSString 类型, 运行时是NSData类型
@synthesize和@dynamic分别什么作用
  • @property有俩个对应的词,一个 是 @synthesize,一个是@dynamic.如果@synthesize 和 @dynamic都没写,那么默认的就是@synthesize var = _var;
    -@synthesieze 的语义是如果你没有手动实现 setter 方法和 getter 方法, 那么编译器会自动为你加上这个俩个方法.
  • @dynamic 告诉编译器:属性的setter与getter方法由用户自己实现,不自动生成.(当然对于 readonly 的属性只需提供getter即可).假如一个属性被声明为 @dynamic var,然后你没有提供 @setter 方法和 @getter 方法,编译的时候没有问题,但是当程序运行到 instance.var = someVar, 由于缺 setter 方法会导致程序崩溃; 或者当运行到 someVar = var 时,由于缺getter方法同样会导致崩溃.编译时没有问题,运行时才执行相应的方法,这就是所谓的动态绑定.
NSString的时候用copy和strong的区别

OC中NSString为不可变字符串的时候,copy和strong都是只分配一次内存,但是如果用copy的时候,需要先判断字符串时候是不可变字符串,如果是不可变字符串,就不再分配控件,如果是可变字符串才分配控件.如果程序中用到NSString的地方特别多,每一次都要先进行判断就会消耗性能,影响用户体验,用strong就不会再进行变短,所以,不可变字符串都可以直接用strong.

NSArray,NSSet,NSDictionary,与NSMutableArray,NSMutableSet, NSMutableDictionary的特性和作用(遇到copy修饰产生变化)

特性:

  • NSArray 表示不可变的数组, 是有序元数集,只能储存对象类型,可通过索引直接访问元数,而且元数类型可以不一样,但是不能进行增删改,NSMutableArray是可变数组,能进行增删改.通过索引查询值很快,但是插入,删除,等效率很低
  • NSSset标识不可变集合,具有稳定性,互异性,无序性的特点,只能访问而不嗯呢修改集合:NSMutableSet可变集合,可以对集合进行增删改.集合通过值查询很快,插入,删除操作极快
  • NSDictionary 表示不可变字典,具有无序性的特点,每个key对应的值是唯一的,可通过key直接取值,NSMutableDictionary表示可变字典,能对字典进行增删改,通过key查询插入和删除都很快.
    作用
  • 数组用于处理一组有序的数据集,比如常用的列表的dataSource要求有序,可通过索引直接访问,效率高
  • 集合要求具有确定性,互异性,无序性,在iOS开发中是比较少使用到的,笔者也不清楚如何说明其作用
  • 字典是键值对数据集,操作字典效率极高,时间复杂度为常量,但是值是无序的,在iOS中,常见的JSON转字典,字典转模型就是之中的一种应用.
请把字符串2015-04-10格式化日期转换为NSDate类型
NSString *timeStr = @"2015-04-10";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd";
formatter.timeZone = [NSTimeZone defaultTimeZone];
NSDate *date = [formatter fateFromString:timeStr];
// 2015-04-09 16:00:00 + 0000
NSLog(@"%@", date);
在一个对象的方法里面:self.name=@object;和name=@object有什么不同
  • 这是老生常谈的话题了,实质上就是问setter方法赋值与成员变量赋值有什么不同.通过点语法self.name实质上就是[self setName];儿name这里是成员变量,直接赋值
  • 一般来说,在对象的方法里成员变量和方法都是可以访问的,我们通常会重写seter方法来执行某些额外的工作.比如说,外部传一个模型过来,那么我会直接重写setter方法,当模型传过来时,也就因为这数据发生了变化,那么视图也需要更新显示,则在赋值新模型的同时也在刷新UI.这样也不用在额外去提供其他方法了
怎样使用performSelector传入3个以上参数,其中一个为结构体
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

因为系统提供的performSelector的api中,并没有提供三个参数.因此,我们只能传数组或者字典,三十数组或者字典自有存入对象类型,而结构体并不是对象类型,那怎么办呢?没有办法,我们只能通过对象放入结构最为属性传递过去了

typedef struct HYBStruct {
    int a;
    int b;
} *my_struct;

@interface HYBObject : NSObject
@property (nonatomic, assign) my_struct arg3;
@property (nonatomic, copy)  NSString *arg1;
@property (nonatomic, copy) NSString *arg2;
@end

@implementation HYBObject
//  在堆上分配内存,我们要手动释放
 - (void)dealloc {
  free(self.arg3);
}
@end

测试:

my_struct str = (my_struct)(malloc(sizeof(my_struct)));
str->a = 1;
str->b = 2;
HYBObject *obj = [[HYBObject alloc] init];
obj.arg1 = @"arg1";
obj.arg2 = @"arg2";
obj.arg3 = str;
[self performSelector:@selector(call:) withObject:obj];
// 在回调时得到正确的数据
- (void)call:(HYBObject *)obj {
    NSLog(@"%d %d", obj.arg3->a, obj.arg3->b);
}
objc中一个对象发送消息[obj foo]和objc_msgSend()函数之间有什么关系

实际上,编译器在编译的时候会转换成objc_msgSedn,大概会像这样:

(void(*))(id, SEL)
((void) objc_msgSend)
((id)obj, sel_registerName("foo"))

也就是说, [obj foo];在objc动态编译时,会被转换成:objc_msgSend(obj,@selector(foo));这样的形式, 但是需要根据具体的参数类型返回值类型进行相应的类型转换.

下面代码输出是什么
@implementation Son: Father

- (id)init {
    self = [super init];
    if (self) {
        NSLog(@"%@", NSStringFromClass([self class]));
        NSLog(@"%@", NSStringFromClass([super class]));
    }
    return self;
}

@end

结果:

NSStringFromClass([self class]) = Son
NSStringFromClass([super class]) = Son

解析:这个题目主要是考察关于Objective-C中对self和super的理解.我们都知道:self是类的隐藏参数,指向当前调用方法的这个类的实例.那么super呢,很多人会想当然的认为"super"和self类似,应该是指向父类的指针吧!这是很普遍的一个误区.其实super是一个 magic keyword,他的本质是个编译器标识符,和self是指向同一个消息接受者!她们俩个的不同点在于:super告诉编译器,调用class这个方法时,要去父类的方法,而不是本类里面的.上面的例子不管调用[self class]还是[super class],接受消息的对象都是当前 son *xxx 这个对象.当使用self调用方法时,会从当前类的方法列表中开始找,如果没有,就从父类中再找;而当使用super时,则会从父类的方法列表中开始找.然后调用父类的这个方法.

若一个类有实例变量NSString *_foo, 调用setValue:forkey:时,可以foo还是_foo作为key
  • 两者都可以
什么时候使用NSMutableArray,什么时候使用NSArray
  • 当数组在程序运行时,需要不断的变化,使用NSMutableArray,当数组在初始化后,便不再改变的,使用NSArray.需要指出的是,使用NSArray只表明的是该数组在运行的时候不会发生改变,即不能往NSAarray的数组里面新增和删除元素,但不表明其数组内的元素的内容不能发生改变.NSArray是线程安全的,NSMutableArray不是线程安全的,多线程使用到NSMutableArray需要注意
类NSObject的哪些方法经常被使用
  • NSObject是Objective-C的基类,其由NSObject类以及一系列协议构成.
  • 其中类方法alloc,class,description 对象方法 init, dealloc, - performSelector:withObject:afterDelay:等经常被使用
什么是简便构造器
  • 简便构造方法一般由CocoaTouch框架提供,如NSNumber+numberWithBool + numberWithChar + numberWithDouble + numberWithFloat + numberWithInt
  • Foundation 下大部分类均有简便构造器方法,我们可以通过简便构造方法,活的系统给我们创建好的对象,并且不需要手动释放
什么是构造器方法,使用构造器的特点
  • 构造方法是对象初始化并且实例的方法
  • 一般构造方法里对类进行一些初始化操作,方法必须要init开头,接下来名称要大写,例如initWithName.initLayout
创建一个对象需要经过哪三个步骤
  • 开辟内存空间
  • 初始化参数
  • 返回内存地址值
get方法的作用是什么
  • 为调用者返回对象内部的成员变量
set方法的作用是什么,set的好处
  • 为调用者设置对象内部的成员变量
    好处
  • 在成员变量的变化时候可以在方法里面做相应的操作,无需写多余的方法
  • 不然数据暴露在外,保证了数据的安全性
  • 对这是的数据进行过滤
结构体当中不能定义OC对象吗
  • 不能,因为结构体当中只能是类型的声明不能进行分配空间
点语法本质是什么,写一个点语法的例子,并写上注释
  • 点语法的本质是方法的调用, 而不是访问成员变量, 当使用点语法时,编译器会自动展开成相应的方法.切记点语法的本质是转换成相应的set和get方法,如果没有set和get方法,则不能使用点语法.
  • 例如有一个Person类 通过@property定义了name和age属性,在提供一个run方法.
Person *person = [Person new];
person.name = @"itcast";调用了person的setName方法
int age - person.age; // 调用了person的age方法
person.run // 调用了person的run方法
id类型是什么,instancetype是什么,有什么区别
  • id类型:万能指针,能作为参数,防范的返回类型
  • isntancetype:只能作为方法的范围类型,并且返回的类型是当前定义类的类型.
成员变量名的命名以下划线开头的好处
  • 与get方法的方法名区分开来
  • 可以和一些其他的局部变量分开来,下划线开头的变量,通常都是类的成员变量
下面这段代码有什么问题
@implementation Person
- (void)setAge:(int)newAge {
self.age = newAge;
}
@end

这个会造成死循环,点语法是方法的调用,会一直走这个方法,_age = age;书写也不规范应该是吧newAge改成age

截取字符串"20|http://www.bai.com"中,"I"字符前面和后面的数据,分别输出他们
NSString *str = @"20|http://ww.baidu.com";
NSSArray *array = [str componentsSeparatedByString:@"|"]:
// 打印前后的数据输出
for (int i = 0; i 
写一个完整的代码,包括声明,实现
// 创建
@protocol MyDelete
@required
- (void)eat:(NSString *)foodName;
@optional
- (void)run;
// 声明
@interface person : NSObject
@end
// 实现
@implement person
- (void)eat:(NSString  *)foodName {
    NSLog(@"吃%@",foodName);
}
- (void)run {
    NSLog(@"run!");
}
@end
isKindOfClass,isMemberOfClass,selector作用分别是什么
  • isKindOfClass, 作用是,某个对象属于某个类型或者继承自某类型
  • isMemberOfClass:某个对象确切属于某个类型
  • selector:通过方法名,获取在内存中函数的入口地址

请分别写出SEL,id,@的意思

  • SEL是"selector"的一个类型,标识一个方法的名字---就是一个方法的入口地址
  • id是一个执行任何一个集成了Object(或者NSObject)类的对象.需要注意的是id是一个指针,所以在使用id的时候不需要添加*
  • @是OC中的指令符号

unsigned int 和 int 有什么区别.假设int长度为65535,请写出unsigned int 与int 的取值范围

  • int:基本整型,当字节数为2事取值范围为-32768~32767, 当字节数为4时,取值范围负的2的31次方到2的31次方减一
    unsigned int: 无符号基本整型,当字节数为2时取值范围为0~65535, 当字节数为4时,取值范围为0到2的32次方减一
Foundation对象与Core Foundation 对象有什么区别
  • Foundation对象是OC的, Core Foundation 对象是C对象
  • 数据类型之间的转换
    -- ARC:bridge_retained(持有对象所有权,F->CF),bridge_transfer(释放对象所有权CF->F)
    -- 非ARC:__bridge
编写一个函数,实现递归删除地址路径下的所有文件
+ (void)deleteFiles:(NSString *)path;{
    // 1. 判断是文件还是目录
    NSFileManager * fileManger = [NSFileManager defaultManager];
    BOOL isDir = NO;
    BOOL isExist = [fileManger fileExistsAtPath:path isDirectory:&isDir];
    if (isExist) {
        // 2. 判断是不是目录
        if (isDir) {
            NSArray * dirArray = [fileManger contentsOfDirectoryAtPath:path error:nil];
            NSString * subPath = nil;
            for (NSString * str in dirArray) {
                subPath  = [path stringByAppendingPathComponent:str];
                BOOL issubDir = NO;
                [fileManger fileExistsAtPath:subPath isDirectory:&issubDir];
                [self deleteFiles:subPath];
            }
        }else{
            NSLog(@"%@",path);
            [manager removeItemAtPath:filePath error:nil];
        }
    }else{
        NSLog(@"你打印的是目录或者不存在");
    }
}

你可能感兴趣的:(《iOS知识点梳理-ObjectC语言》)