美文网首页
ios细小知识点总结

ios细小知识点总结

作者: 伶俐ll | 来源:发表于2018-07-12 17:23 被阅读11次

    一、 defin定义的宏和const定义的常量的区别

    • define定义的常量,程序在预处理阶段只是直接用define定义的内容进行了替换,没有数据类型,所以编译时不能进行数据类型检验,并且在字符替换可能会产生意料不到的错误(边际效应)。const定义的常量有数据类型,在编译时进行严格的类型检验,可以避免出错。
    • 在程序运行时,常量表中并没有用define定义的常量,系统不为它分配内存。const定义的常量,在程序运行时在常量表中,系统为它分配内存。
    • 在程序执行过程中const定义的只读变量在程序运行过程中只有一份拷贝,而 #define定义的常量在内存中可能有若干个拷贝,因此const可以节省空间,避免不必要的内存分配。
    • 有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。

    二、static关键字的作用

    • 用static声明局部变量,使其变为静态存储方式(静态数据区),作用域不变。
    • 用static声明外部变量,其本身就是静态变量,这只会改变其连接方式,使其只在本文件内部有效,而其他文件不可连接或引用该变量。
    • 使用static用于函数定义时,使得函数只在本文件内部有效,对其他文件是不可见的,而且在内存中只有一份,普通函数在每个被调用中维持一份拷贝。
    • static变量程序运行过程中只被初始化一次。

    三、内存分区情况

    • 代码区
      存放函数二进制代码
    • 数据区
      系统运行时申请内存并初始化,系统退出时由系统释放,存放全局变量,静态变量,常量
    • 堆区
      1、通过malloc等函数或new等操作符动态申请得到,需程序员手动申请和释放,容易产生内存泄漏。
      2、频繁的new/delete会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。
    • 栈区
      1、由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
      2、先进先出,一一对应,不会有单独的一块内存快从栈中间弹出。

    四、OC中的反射机制

    • class反射
      //通过类名的字符串形式实例化对象
      Class class = NSClassFromString(@"NSObject");
      NSObject *object = [[class alloc]init];
     //将类名变为字符串   
      NSString *className = NSStringFromClass([NSObject class]);
    
    • SEL反射
    //通过方法的字符串形式实例化方法
     SEL selector = NSSelectorFromString(@"setName:");
      [object performSelector:selector withObject:@"a"];
     //将方法变成字符串       
     NSString str = NSStringFromSelector(@selector(setName));
    

    五、@synthesize和@dynamic分别有什么作用

    • @synthesize的意义是,如果开发者没有手动实现settergetter方法,那么编译器会自动为你加上这两个方法。默认就是@synthesize var = _var
    • @dynamic告诉编译器,属性的settergetter方法由用户自己实现,不自动生成。例如,一个属性被声明为@dynamic var,然后用户没有手动实现settergetter方法,编译的时候没有问题,但是当程序运行到instance.var = somevar时,由于缺少setter方法会导致程序崩溃;或者运行到somevar = instance.var时,由于缺少getter方法同样会导致崩溃。

    六、super关键字

    下列代码中Student继承自PersonPerson继承自NSObject

    #import "Student.h"
    @implementation Student
    - (instancetype)init
    {
        if (self = [super init]) {
            NSLog(@"[self class] = %@", [self class]); //Student
            NSLog(@"[self superclass] = %@", [self superclass]); //Person
            NSLog(@"[super class] = %@", [super class]); //Student
            NSLog(@"[super superclass] = %@", [super superclass]); //Person
        }
        return self;
    }
    

    原理解析:
    super调用,底层会转换为objc_msgSendSuper2函数的调用,_objc_msgSendSuper2函数内接收2个参数
    struct objc_super2SEL``struct objc_super2结构如下:

    struct objc_super2 {
        id receiver;
        Class current_class;
    };
    

    receiver是消息接收者,current_class是receiver的Class对象,也就是当前类对象,objc_msgSendSuper2函数会在内部获取当前类对象的父类,并且从父类开始查找方法。

    image.png

    七、isKindOfClass 与 isMemberOfClass

    • isMemberOfClass: isKindOfClass:对象方法底层实现
    - (BOOL)isMemberOfClass:(Class)cls {
       // 直接获取实例类对象并判断是否等于传入的类对象
        return [self class] == cls;
    }
    
    - (BOOL)isKindOfClass:(Class)cls {
       // 向上查询,如果找到父类对象等于传入的类对象则返回YES
       // 直到基类还不相等则返回NO
        for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
            if (tcls == cls) return YES;
        }
        return NO;
    }
    
    • isKindOfClass:isKindOfClass:类方法底层实现
    // 判断元类对象是否等于传入的元类元类对象
    // 此时self是类对象 object_getClass((id)self)就是元类
    + (BOOL)isMemberOfClass:(Class)cls {
        return object_getClass((id)self) == cls;
    }
    
    // 向上查找,判断元类对象是否等于传入的元类对象
    // 如果找到基类还不相等则返回NO
    // 注意:这里会找到基类
    + (BOOL)isKindOfClass:(Class)cls {
        for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
            if (tcls == cls) return YES;
        }
        return NO;
    }
    

    由以上可知,下面代码打印结果:

    NSLog(@"%d",[Person isKindOfClass: [Person class]]); //0
    NSLog(@"%d",[Person isKindOfClass: object_getClass([Person class])]); //1
    NSLog(@"%d",[Person isKindOfClass: [NSObject class]]);//1
    

    1、类方法是获取元类对象与传入的参数进行比较,但是第一行我们传入的是类对象,因此返回NO。
    2、同上,此时我们传入Person元类对象,此时返回YES。
    3、由于基元类的superclass指针指向基类类对象,因此返回YES。

    八、 为什么 Objective-C 对象存储在堆上而不是栈上

    • 在Objective-C中,对象通常是指一块有特定布局的连续内存区域。
    • 我们通常这样创建一个对象:NSObject*obj=[[NSObjectalloc]init];这行代码创建了一个NSObject类型的指针obj和一个NSObject类型的对象,obj指针存储在栈上,而其指向的对象则存储在堆上(简称为堆对象)。
    • 目前 Objective-C 并不支持直接在栈上创建对象(简称为堆对象),但可以通过如下方式间接地创建:
      struct { 
        Class isa; 
      } fakeNSObject; 
      fakeNSObject.isa = [NSObject class]; 
      NSObject *obj = (NSObject *)&fakeNSObject; 
      NSLog(@"%@", [obj description]); 
      

    栈对象 obj 也能正常工作,由此可见栈对象和堆对象都是可行的,但为什么 Objective-C 不默认使用栈对象呢?
    栈对象优缺点
    1、优点

    • 速度 :在栈上创建对象是非常快的,因为很多东西在编译时就确定了,运行时分配空间几乎不耗时;相对而言在堆上创建对象就非常耗时。
    • 简单 :栈对象的生命周期是确定的,对象出栈以后就会被释放,不会存在内存泄漏,但这同时也是栈对象的最大缺点。

    2、缺点

    • 生命周期固定 :Objective-C 变量有效范围是由 “{}” 包含的块来决定的,也就是说栈对象的生命周期仅限于其所在的块里,出了块立马会被释放。一个对象被创建以后有可能会通过方法调用传递到别的方法,当栈对象的创建方法返回时,栈对象会被一起 pop 出栈而释放,导致其没法在别处被继续持有。此时 retain 操作会失效,除非用 copy 方法在想持有该栈对象的地方重新拷贝一份属于自己的栈对象。因此,栈对象回给对象的内存管理造成相当大的麻烦。
    • 空间 :现代操作系统的栈和线程绑定,而栈空间是有限的,具体如下:
      512 KB (secondary threads)
      8 MB (OS X main thread)
      1 MB (iOS main thread)
      因此对象如果都在栈上创建不太现实,而堆只要物理内存不告警可以无限制使用。

    综合以上优缺点,Objective-C 选择用堆存储对象。

    九、id和instancetype的区别

    1、instancetype 可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象。
    2、在ARC环境下:instancetype用来在编译期确定实例的类型,而使用id的话,编译器不检查类型, 运行时检查类型。在MRC环境下:instancetype和id一样,不做具体类型检查。

    //person类
    @interface Person : NSObject
    +(id)person;
    @end
    
    @implementation Person
    +(id)person{
        return [[self alloc]init];
    }
    @end
    
    //Student类
    @interface Student : Person
    -(void)test;
    @end
    @implementation Student
    -(void)test{
        NSLog(@"---------");
    }
    @end
    
    //在ARC环境下,遍历构造器方法创建的Person对象返回值是id类型,编译时不会检查类型,编译不会报错,但是当返回类型是instancetype的时候,编译器就会检查数据类型,发现Person类并没有test方法,因此在编译的时候就会报错。
     [[Person person] test];
    

    3、instancetype只能作为返回值,id可以作为参数。

    十、项目中定位用的网络的还是GPS

    iOS设备能提供3种不同途径进行定位:
    1、 蜂窝式移动电话基站 (iOS优化:无网基站定位)
    2、Wifi (iOS优化:无网WIFI定位)
    3、GPS卫星 (iOS优化:A-GPS定位)
    而iPhone的GPS与纯粹的GPS定位不同,称为A-GPS,即辅助GPS.(比GPS更优,不过GPS也分芯片和性能的,不是说所有的AGPS比所有的GPS都好)因为GPS定位中最耗时、最耗电的就是获取当前天上的卫星信息,哪些卫星可见、在什么位置、时钟是多少等等,这个过程可能花费数十秒甚至几分钟,而AGPS就是利用网络,首先将基站定位或者WIFI定位获得的大概位置发到远程服务器,有服务器进行查询和计算,得出这个位置下当前卫星信息,反馈给iOS设备,iOS设备就可以直接用这些信息来接受卫星信号,不用自己去扫描分析了。这样可以极大提高定位速度,将初次定位时间缩短到1~2秒完成。
      A-GPS优点是定位快,缺点是需要网络,但也只是在初次定位时需要网络,因为一旦卫星信息返回,在有限时间和范围内,这些信息无须改变,之后的GPS定位就不再需要联网,都是直接用这些卫星参数接受信息了。

    • iOS 不像Android系统在定位服务编程时,可以指定采用哪种途径进行定位。iOS的API把底层这些细节屏蔽掉了,开发人员和用户并不知道现在设备是采用 哪种方式进行定位的,iOS系统会根据设备的情况和周围的环境,采用一套最佳的解决方案。
    • 在iOS设备上,上述定位方式会综合应用,一般地,可能先按照最快的“无网基站定位”返回一个位置,当有网络连接时,在用有网基站定位更新位置,然后,利用AGPS上网查询卫星星图,最后,在能收到GPS信号的情况下,转为使用GPS定位。
    • 根据当前信号情况和网络环境,iOS可能在上述方式之间反复迭代,不一定一致特定步骤或者方式,而且随着iOS升级,定位顺序和规则可能改变。

    参考文章:https://zhidao.baidu.com/question/1962374999608474260.html

    十一栈和队列的区别,栈和堆的区别

    栈和队列的区别:
    • 栈的插入和删除操作都是在一端进行的,而队列的操作却是在两端进行的。
    • 栈是先进后出,队列是先进先出。
    • 栈只允许在表尾一端进行插入和删除,队列只允许在表尾一端进行插入,在表头一端进行删除。
    栈和堆的区别:
    • 栈区:由编辑器自动分配释放,存放函数的参数值,局部变量的值等(基本类型值)。
    • 堆区:由程序员分配释放,若程序员不释放,程序结束时可能有OS回收(引用类型值)。
    • 栈(数据结构):一种先进后出的数据结构。
    • 堆(数据结构):堆可以被看成是一棵树,如:堆排序。

    相关文章

      网友评论

          本文标题:ios细小知识点总结

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