6. key 和 keypath 的区别
在iOS开发中经常碰到重载方法有传key和keypath两种,但是一直搞不清楚他们两的区别,最近研究了一下官网KVC编程对key和keypath的区别有了具体的认识:
例如:
KVC编程时setValue(value: AnyObject?, key: String)和setValue(value: AnyObject?, keypath: String)
key:只能接受当前类所具有的属性,不管是自己的,还是从父类继承过来的,如view.setValue(CGRectZero(), key: “frame”);
keypath: 除了能接受当前类的属性,还能接受当前类属性的属性,即可以接受关系链,如view.setValue(5, keypath: “layer.cornerRadius”)
7. 类别 与 拓展的区别。
- 类扩展 (Class Extension也有人称为匿名分类)
作用:
能为某个类附加额外的属性,成员变量,方法声明
一般的类扩展写到.m文件中
一般的私有属性写到类扩展
使用格式:
@interface Mitchell()
//属性
//方法
@end
- 与分类的区别
分类的小括号中必须有名字
@interface 类名(分类名字)
/*方法声明*/
@end
@implementation类名(分类名字)
/*方法实现*/
@end
分类只能扩充方法,不能扩展属性和成员变量(如果包含成员变量会直接报错)。
如果分类中声明了一个属性,那么分类只会生成这个属性的set、get方法声明,也就是不会有实现。
举例说明:如果我们分别在,类扩展与分类中添加了两个属性,
接下来在初始化方法中分别赋值,
大家会看到在为在分类中所声明的属性textOne赋值的时候,崩溃了,那么我们来查看一下崩溃的原因:
意思是说,我们所创建的对象中并没有textOne这个属性。也就是说虽然我们再类别中声明属性不会报错,但是@property并没有自动为我们设置的属性生成set、get方法。
再说一下我们为什么不能包含类的.m文件,因为这样会重复包含另一个类的实现文件。
8. block 和 函数指针 有什么区别。
- 函数指针是对一个函数地址的引用,这个函数在编译的时候就已经确定了。而block是一个函数对象,是在程序运行过程中产生的。在一个作用域中生成的block对象分配在栈(stack)上,和其他所有分配在栈上的对象一样,离开这个作用域,就不存在了。
Block允许开发者在两个对象之间将任意的语句当做数据进行传递,往往这要比引用定义在别处的函数直观。
9. 如何向 NSArray 中加入结构体,是深拷贝还是浅拷贝?*
- 比较常见的结构体:CGPoint ,CGSize,CGRect。。。。。。我们如何存放到数组中呢?因为是结构体不是对象,不能添加到数组中,解决方法:把这些常见的结构装换成对象,让后放进去,取出来在装换成结构体使用。我们想到了NSValue使用方法如下:
CGPoint point = CGPointMake(0, 0);
NSMutableArray *array = [[NSMutableArray alloc]initWithCapacity:0];
NSValue *value = [NSValue valueWithCGPoint:point];
[array addObject:value];
取出数组之后的对象的使用:
NSValue *tmpValue = array[0];
CGPoint tmpPoint = [tmpValue CGPointValue];
下面是一些常见的结构体使用方法是一样的
@interface NSValue (NSValueUIGeometryExtensions)
+ (NSValue *)valueWithCGPoint:(CGPoint)point;
+ (NSValue *)valueWithCGVector:(CGVector)vector;
+ (NSValue *)valueWithCGSize:(CGSize)size;
+ (NSValue *)valueWithCGRect:(CGRect)rect;
+ (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform;
+ (NSValue *)valueWithUIEdgeInsets:(UIEdgeInsets)insets;
+ (NSValue *)valueWithUIOffset:(UIOffset)insets NS_AVAILABLE_IOS(5_0);
- (CGPoint)CGPointValue;
- (CGVector)CGVectorValue;
- (CGSize)CGSizeValue;
- (CGRect)CGRectValue;
- (CGAffineTransform)CGAffineTransformValue;
- (UIEdgeInsets)UIEdgeInsetsValue;
- (UIOffset)UIOffsetValue NS_AVAILABLE_IOS(5_0);
@end
- 2、自定义结构体的存储
同样是先转换NSValue对象再加入数组中,代码如下:
// 自定义的结构体
struct Test {
int ID;
CGFloat height;
};
typedef struct Test Test;
// 封装数据
Test tmpTest;
tmpTest.height = 80.0;
tmpTest.ID = 100;
NSLog(@"id==%d,height==%f",tmpTest.ID,tmpTest.height);
NSValue *customValue = [NSValue valueWithBytes:&tmpTest objCType:@encode(struct Test)];
// 取出数据
Test tmpTest1;
[customValue getValue:&tmpTest1];
NSLog(@"id==%d,height==%f",tmpTest1.ID,tmpTest1.height);
10. 通知是同步还是异步
与JavaScript中的事件机制不同,iOS里的事件广播机制是同步的,默认情况下,广播一个通知,会阻塞后面的代码:
-(void) clicked
{
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center postNotificationName:@"event_happend" object:self];
NSLog(@"all handler done");
}
按下按钮后,发送一个广播,此前已经注册了2个此事件的侦听者
-(id) init
{
self = [super init];
if(self){
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(whenReceive:) name:@"event_happend" object:nil];
}
return self;
}
-(void) whenReceive:(NSNotification*) notification
{
NSLog(@"im1111");
}
-(id) init
{
self = [super init];
if(self){
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(whenReceive:) name:@"event_happend" object:nil];
}
return self;
}
-(void) whenReceive:(NSNotification*) notification
{
NSLog(@"im22222");
}
执行这段代码,首先会输出im1111,然后是im22222,最后才是all handler done。调试发现,代码始终是跑在同一个线程中(广播事件的线程),广播事件之后的代码被阻塞,直到所有的侦听者都执行完响应
所以,由于NotificationCenter的这个特性,如果希望广播的事件异步处理,则需要在侦听者的方法里开启新线程。应该把Notification作为组件间解耦的方式,而不是利用它来实现异步处理.
发生事件,通知中心广播,有可能有多个监听者,设计上使用同步的方式,能够保证所有的监听者都对通知作出响应!不会产生遗漏.