美文网首页
iOS 面试题

iOS 面试题

作者: Jimmy_N9 | 来源:发表于2019-12-10 18:16 被阅读0次

    问题:

    1. 请说一下栈区与堆区的区别?你所知道的分区还有哪些?

    2. 分别说你对strongcopy, assignweak的理解。并说出其两两的区别。

    3. 这个写法有什么问题?@property (copy) NSMutableArray* array;

    4. @synthesize与@dynamic有什么作用?

    5. 如何在categoryprotocol中添加属性?

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

    阅读以上代码,会输出什么?
    7.使用block时什么情况会发生循环引用?如何解决?

    1. OC 中的有哪些方法实现多线程?请说一下其区别
    2. 如何使用GCD同步若干个异步调用?(如加载多张图片,然后合成一张图)
    3. 阅读以下代码:
      (1):
        NSLog(@"1");
        dispatch_async(dispatch_get_main_queue(), ^{
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
                NSLog(@"2");
            });
            NSLog(@"3");
        });
        dispatch_sync(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"4");
        });
        NSLog(@“5”);
    

    (2):

    dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"test");
        });
    

    (1)请写打印的顺序:
    (2)主线程下运行会出现什么情况?

    1. Runloop 的 mode的作用是什么?
    2. 使用NSTimer时该注意些什么?
    3. 你使用runtime 实现过些什么?
    4. iOS的数据持久化有哪些?
    5. 判断数组中是否有重复值。必须保证额外空间复杂度为O(1)。

    答案:

    (1)栈区的地址从高到低分配,堆区是由低到高分配
    (2)栈区的内存分配是连续的,堆区的内存分配是不连续的
    (3)栈区的内存操作效率高,由于堆区分配的内存结构比较复杂,所以操作起来效率比栈区低。
    其他分区:
    全局区、常量区、代码区。

    2 :
    strongcopy都会使引用计数加1,但strong是两个指针指向同一个内存地址,copy会在内存里拷贝一份对象,两个指针指向不同的内存地址,以及copy修饰可变对象时要额外注意。
    assign 适用于基本数据类型,weak是适用于NSObject对象,并且是一个弱引用。
    weak修饰的对象在释放之后,指针地址会被置为nil。所以现在一般弱引用就是weak
    assign其实也可以用来修饰对象,那么我们为什么不用它修饰对象呢?因为被assign修饰的对象(一般编译的时候会产生警告:Assigning retained object to unsafe property; object will be released after assignment)在释放之后,指针的地址还是存在的,也就是说指针并没有被置为nil,造成野指针。对象一般分配在堆上的某块内存,如果早后续的内存分配中,刚好分配到这块地址,程序就会崩掉。
       那为什么可以用assign修饰基本数据类型?因为基础数据类型一般分配在栈区,栈区的内存会由系统自动处理,不会造成野指针
    3 :
    1、添加,删除,修改数组内的元素的时候,程序会因为找不到对应的方法而崩溃.因为 copy 就是复制一个不可变 NSArray的对象;
    2、使用了 atomic属性会严重影响性能

    4 :
    @property有两个对应的词,一个是 @synthesize,一个是 @dynamic。如果 @synthesize@dynamic都没写,那么默认的就是@syntheszie var = _var;
    @synthesize的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法。
    @dynamic 告诉编译器:属性的 settergetter方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需提供 getter 即可)。假如一个属性被声明为@dynamic var,然后你没有提供 @setter方法和 @getter 方法,编译的时候没问题,但是当程序运行到instance.var = someVar,由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = var时,由于缺 getter方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

    5 :
    protocol中使用 property只会生成 settergetter方法声明,我们使用属性的目的,是希望遵守我协议的对象能实现该属性
    category 使用 @property也是只会生成 settergetter 方法的声明,如果我们真的需要给 category 增加属性的实现,需要借助于运行时的两个函数:
    objc_setAssociatedObject
    objc_getAssociatedObject

    6 :都输出 Son

    7 :一个对象中强引用了block,在block中又强引用了该对象,就会发射循环引用。
    解决方法是将该对象使用__weak或者__block修饰符修饰之后再在block中使用。
    id __weak weakSelf = self; 或者 __weak typeof(&*self)weakSelf = self该方法可以设置宏
    id __block weakSelf = self;
    或者将其中一方强制制空 xxx = nil

    8 :
    1、 NSThread
    2、Cocoa NSOperation (使用NSOperation和NSOperationQueue)
    3、GCD(Grand Central Dispatch)
    4、 pthread

    线程相关

    9 :
    使用Dispatch Group追加block到Global Group Queue,这些block如果全部执行完毕,就会执行Main Dispatch Queue中的结束处理的block。

    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{ /*加载图片1 */ });
    dispatch_group_async(group, queue, ^{ /*加载图片2 */ });
    dispatch_group_async(group, queue, ^{ /*加载图片3 */ }); 
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            // 合并图片
    });
    

    10: (1)1、4、5、3、2
    (2)Crash

    11: model 主要是用来指定事件在运行循环中的优先级的,分为:
    NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默认,空闲状态
    UITrackingRunLoopMode:ScrollView滑动时
    UIInitializationRunLoopMode:启动时
    NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合
    苹果公开提供的 Mode 有两个:

    NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
    NSRunLoopCommonModes(kCFRunLoopCommonModes)
    

    12: 1. 循环引用问题 2. 在滑动时注意 Runloop 的mode问题

    13: 开放性问题,动态添加类,属性,方法和方法交换等等。

    14: plist ,归档,userdefault , coredata , sqlite 等等

    15:
    如果没有空间复杂度限制,用哈希表实现。 时间和空间复杂度都是O(N)。

    如限制空间复杂度,则应先排序,后判断,排好序后的重复元素就对相邻,方便判断。

    考察经典排序算法,空间复杂度限制。O(1)的是堆排序,当不能使用递归的实现方式,因为递归法下堆排序的空间复杂度为O(logN),函数栈深度为logN,所以应该改为非递归版本的堆排序。

    //堆来做

    #include<iostream>
    #include<vector>
    using namespace std;
    
    void swap(int*a,int *b){
        int tmp=*a;
        *a=*b;
        *b=tmp;
    }
    void heapSort(vector<int>&a,int n){
        for(int i=0;i<n;i++){
            //对n-i调整大顶堆
            for(int j=n-i-1;j>0;j--){
                int pre=(j-1)/2;
                if(j%2==0){
                    pre=(j-2)/2;
                }
                if(a[j]>a[pre]){
                    swap(&a[j],&a[pre]);
                }
            }
            swap(&a[0],&a[n-1-i]);
        }
    }
    bool checkDuplicate(vector<int> a, int n) {
        // write code here
        heapSort(a,n);
        for(int i=1;i<n;i++){
            if(a[i]==a[i-1]){
                return true;
            }
        }
        return false;
    }
    int main(){
        int v[]={4,6,1,3,5,6,2};
        //int v[]={1,1};
        vector<int> a(v,v+sizeof(v)/sizeof(int));
        cout<<checkDuplicate(a,a.size())<<endl;
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:iOS 面试题

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