iOS 每天一道面试题

同为菜逼,共同努力。

1.nil Nil NULL NSNull 区别。

nil:指向oc中对象的空指针,针对对象。

Nil:指向oc中类的空指针,针对类。

NULL:指向其他类型的空指针,如一个c类型的内存指针,基本数据类型为空,基本类型。

NSNull:在集合对象中,表示空值的对象。

参考博客这是我发现写的比较详细的博客.

2.你是否接触过oc中的反射机制?简单聊一下概念和使用.

    //    • class反射
    //    • 通过类名的字符串形式实例化对象
    Class class1 = NSClassFromString(@"UILabel");
    id label = [[class1 alloc ]init];
    NSLog(@"label = %@",label);
    //    • 将类名变为字符串
    Class class2 =[UILabel class];
    NSString *className = NSStringFromClass(class2);
    NSLog(@"className = %@",className);

    Student *stu = [[Student alloc] init];
    //    • SEL的反射
    //    • 通过方法的字符串形式实例化方法
    SEL selector = NSSelectorFromString(@"setName:");
    [stu performSelector:selector withObject:@"GanMaoShen"]; //注意如果有两个参数,使用两个withObject:参数;
    NSLog(@"stu.name =%@",stu.name);
    //    • 将方法变成字符串
    NSString *select =  NSStringFromSelector(@selector(testVoidFuncWithTestParam:));
    NSString *select2 =  NSStringFromSelector(_cmd);
    NSLog(@"select =%@ select2 = %@",select,select2);
2017-03-27 20:19:07.658 test[10559:3059755] label = >
2017-03-27 20:19:07.659 test[10559:3059755] className = UILabel
2017-03-27 20:19:07.659 test[10559:3059755] stu.name =GanMaoShen
2017-03-27 20:19:07.659 test[10559:3059755] select =testVoidFuncWithTestParam: select2 = viewDidLoad

3.Block的传值,传址,内存管理,循环引用(retain cycle)。(狠补了一下block的知识,发现block中很多知识点,所以还是要弄透)

两篇很好的block基础博客
block的用法,定义.
block两个界面的传值.

void test1()
{
  int a = 10;
}
void test2()
{
    __block int a = 10;
}
void test3()
{
    static int a = 10;
}
int a = 10;
void test4()
{
}
总结:block中只有普通局部变量(test1)是传值,其他情况(test2,test3,test4)都是传址。
#block的内存管理
ARC下:
- block可以使用copy和strong,并且是一个对象。

#Block如果没有引用外部变量
保存在全局区(MRC/ARC一样)
#Block如果引用外部变量
ARC保存在 堆区; MRC保存在 栈区必须用copy修饰block;

推荐博客深入浅出-iOS Block原理和内存中位置

block循环引用
1.如果block代码块的内部,使用了外面的强引用对象,block代码块的内部会自动产生一个强引用,引用着该对象,不会销毁,造成循环引用.
解决:下面代码在block外部实现.
__weak typeof(self) weakSelf = self; 
#define WeakSelf(type)  __weak typeof(type) weak##type = type;
2.但是如果在block内部使用延时操作的还使用弱指针的话会取不到该弱指针,需要在block内部再将弱指针强引用一下.
__strong typeof(self) strongSelf = weakSelf;
#define StrongSelf(type)  __strong typeof(type) strong##type = weak##type;

关于循环引用很好的博客Swift与OC真正去理解Block解决循环引用的技巧

4.如何在@category和@protocol中添加@property

首先你要知道category和protocol和作用和区别,同时回顾这道题的同时,同时回顾extension 和category。
extension看起来很像一个匿名的category,但是extension和有名字的category几乎完全是两个东西。 extension在编译期决议,它就是类的一部分,在编译期和头文件里的@interface以及实现文件里的@implement一起形成一个完整的类,它伴随类的产生而产生,亦随之一起消亡。extension一般用来隐藏类的私有信息,你必须有一个类的源码才能为一个类添加extension,所以你无法为系统的类比如NSString添加extension。
更深入一点的话我推荐这个帖子。iOS 类别不能添加属性原理?

@dynamic 和 @synthesize的区别:
在@implementation 中通过@dynamic xxx 告诉编译器、xxx属性的setter、getter方法由开发者自己来生成
@ synthesize xxx = _xxx; 告诉编译器、xxx属性的setter、getter方法由编译器来生成、同时用_xxx 来合成 成员变量

好,步入正题。

4.1@protocol中添加property

在protocol中添加property时,其实就是声明了 getter 和 setter 方法,在实现这个protocol协议的类中,我们要自己手动添加实例变量,并且需要实现setter/getter方法,实现setter/getter方法有两种方式,一种是自动生成(@synthesize) ,另一种是手动生成(@dynamic)此时又有了拓展问题(@synthesize和@dynamic的作用 见 题5)

@protocol PersonDelegate 
@property (nonatomic, copy) NSString *name;
@end
//personn类
@interface Person : NSObject
@end
#import "Person.h"
@interface Student : NSObject 
- (void)testLog;
@end
#import "Student.h"

@implementation Student
//自动实现setter和getter方法
@synthesize name;

- (void)testLog {
    NSLog(@"self.name=%@",self.name);
}

@end

手动实现setter和getter

#import "Person.h"
@interface Student2 : NSObject 
{
    //声明一个实例变量
    NSString *_name;
}
- (void)testLog;
@end

#import "Student2.h"

@implementation Student2
@dynamic name;
- (void)testLog {
    NSLog(@"self.name=%@",self.name);
}
- (void)setName:(NSString *)name
{
    _name = name;
}
- (NSString *)name
{
    return _name;
}
@end
    Student *stu1 = [Student new];
    stu1.name = @"testName";
    [stu1 testLog];
    Student2 *stu2 = [Student2 new];
    stu2.name = @"testName";
    [stu2 testLog];

关于category实现property主要是利用runtime的关联方法(mjrefresh中也有用到)。

objc_setAssociatedObject   objc_getAssociatedObject
@interface Person (Test)
@property (nonatomic, copy) NSString *tmpName;
- (void)testLog;
@end
#import "Person+Test.h"
#import 

@implementation Person (Test)
- (void)setTmpName:(NSString *)tmpName
{
    objc_setAssociatedObject(self, @selector(tmpName), tmpName, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)tmpName
{
    return objc_getAssociatedObject(self, @selector(tmpName));
}
- (void)testLog {
    NSLog(@"self.name=%@",self.tmpName);
}
@end
    Person *p1 = [Person new];
    p1.tmpName = @"tmpName";
    [p1 testLog];

当然还有一种利用临时变量的方法完成添加属性的方法。参考博客
iOS Category 和 Protocol 中的 Property 你们真的会了么?

你可能感兴趣的:(iOS 每天一道面试题)