美文网首页
iOS面试题-代码篇

iOS面试题-代码篇

作者: 洁简 | 来源:发表于2018-03-12 14:05 被阅读132次

对于语句NSString *obj = [[NSData alloc] init]; obj在编译时和运行时分别是什么类型的对象?

编译时是NSString的类型;运行时是NSData类型的对象。

在一个对象的方法里面:self.name = @"object";和 _name = @"object"有什么不同吗?

self.name = @"object"; 是通过点语法修改属性name的值。
本质上使用的是name属性的setter方法进行的赋值操作,实际上执行的代码是
[self setName:@"object"];
例如:
    @property(nonatomic, strong) NSString *name;
    //根据@property关键词,系统自动生成setter方法。
    - (void)setName:(NSString *)name{
        //根据strong关键词
        [name retain];  //内存计数+1
        [_name release];    //把之前指针指向的内容内存计数-1
        _name = name; //指向新内容
    }
而 _name = @“object”; 只是单纯的把‘_name’指针指向‘@"object"’字符串对象所在的地址, 没有调用方法。

这段代码有什么问题吗?

-(void)setAge:(NSString *)age { 
  self.age = age; 
}
在age属性的setter方法中,不能通过点语法给该属性赋值。
会造成setter方法的循环调用。最终导致程序崩溃.因为self.age = newAge; 本质上是在调用 [self setAge:newAge]; 方法。
解决循环调用的方法是方法体修改为 _age = age;

你对@interface中的成员变量和@property声明的属性的理解。

@interface AA: NSObject{
    NSString *_name; //成员变量
}
@property NSString *age; //属性

如上所示:
属性拥有setter和getter方法 外加_age成员变量。
_name只是成员变量, 没有setter和getter方法。

以下代码运行结果如何?

-(void)viewDidLoad  {  
    [super viewDidLoad];  
    NSLog(@"1"); 
    dispatch_sync(dispatch_get_main_queue(), ^{  
        NSLog(@"2");  
    });  
    NSLog(@"3");  
}
结果:只会打印1 然会就会线程卡死
因为dispatch_get_main_queue()得到的是一个串行队列,串行队列的特点: 一次只调度一个任务,队列中的任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
  同步(sync) 操作,它会阻塞当前线程并等待 Block 中的任务执行完毕,然后当前线程才会继续往下运行
  dispatch_sync提交一个打印任务NSLog(@”2”)到主线程关联的串行队列中,主线程关联的串行队列现在有一个viewDidLoad任务,
  打印任务NSLog(@”2”)排在viewDidLoad后面,队列FIFO(先进先出)的原则,打印任务NSLog(@”2”);
  想要得到执行必须等到viewDidLoad执行完毕后才能得到执行,但是viewDidLoad想要执行完毕必须要等打印任务NSLog(@”2”)执行完毕,所以就卡死在这了。
然而实际开发中很少用到,当然注意下还是有必要的.

用预处理指令#define声明一个常数,用以表明一年中有多少秒

#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)_U_LONG
这个问题可以简单考察对于define的基本使用,
如果意识到这个表达式将使一个16位机的整型数溢出-要用到长整型符号,告诉编译器这个常数是的长整型数。
如果你在你的表达式中用到_U_LONG(表示无符号长整型),会更好.
另外如果是较早的答案会是UL,但是目前已经由_U_LONG代替
还有一个类似的题目:写一个”标准"宏MIN ,这个宏输入两个参数并返回较小的一个。
#define MIN(A,B) ((A) <= (B) ? (A) : (B))    注意写法即可

下面的代码输出结果是什么?

@implementation Son : Father
- (id)init {
    self = [super init];
    if (self) {
        NSLog(@"%@", NSStringFromClass([self class]));
        NSLog(@"%@", NSStringFromClass([super class]));
    }
    return self;
}
@end
// 都是son。
self是类的隐藏参数,指向当前调用方法的这个类的实例。而 super 是一个 Magic Keyword, 它本质是一个编译器标示符,和 self 是指向的同一个消息接受者。
上面的例子不管调用[self class]还是[super class],接受消息的对象都是当前 Son *xxx 这个对象。
而不同的是,super是告诉编译器,调用 class 这个方法时,要去父类的方法,而不是本类里的。
当使用 self 调用方法时,会从当前类的方法列表中开始找,如果没有,就从父类中再找;
而当使用 super 时,则从父类的方法列表中开始找。然后调用父类的这个方法。

单例写法

+ (instancetype)sharedInstance {
    static CJManage *manage = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manage = [[CJManage alloc] init];
    });
    return manage;
}
当然这种写法alloc,new,copy,mutableCopy方法不可以直接调用。个人认为没必要因为这就是单例就这样创建就好.
单例的问题:单例对象一旦建立,对象指针是保存在静态区的,单例对象在堆中分配的内存空间,会在应用程序终止后才会被释放。
单例类无法继承,因此很难进行类的扩展。另外还要注意循环引用问题.

下列代码输出什么

void test1() {
    int a = 10;
    void (^block)(void) = ^{
        NSLog(@"a is %d", a);
    };
    a = 20;
    block(); // 10
}
void test2(){
    __block int a = 10;
    void (^block)(void) = ^{
        NSLog(@"a is %d", a);
    };
    a = 20;
    block(); // 20
}
代码已给出答案,这是因为block所在函数中的,捕获自动变量。但是不能修改它,不然就是“编译错误”。
但是可以改变全局变量、静态变量、全局静态变量。
首先不能修改自动变量的值是因为:block捕获的是自动变量的const值,名字一样,不能修改
可以修改静态变量的值:静态变量属于类的,不是某一个变量。由于block内部不用调用self指针。所以block可以调用。
因此block不能修改自动变量的值,可以使用__block修饰符来解决。

相关文章

网友评论

      本文标题:iOS面试题-代码篇

      本文链接:https://www.haomeiwen.com/subject/yrxonxtx.html