美文网首页
ios 关键字

ios 关键字

作者: 愤斗的小蚂蚁 | 来源:发表于2020-05-11 15:10 被阅读0次

    目录
    01 static
    02 extern
    03 const
    04 @property、@synthesize、@dynamic

    01 static

    1. 修饰局部变量:只会初始化一次,值存储一份;只在当前作用域内被使用;可延长局部变量的生命周期。
    2. 修饰全局变量:在类外部不使用static修饰属性为全局变量,在项目工程全局范围内有效,即使没有引用头文件,也可以使用extern 访问声明全局变量(并没有分配内存),不能用于实现;使用static修饰全局变量,只在当前文件内有效,外部类不可以访问。
    3. 警告: static 写在interface外面编译是没有错误的,但是编译器会报警告,这么说这样的写法是不被编辑器认可的。(XCode11.4.1未发现警告)
      错误:static 写在interface里面会直接报错,显然这样的语法是不被认可的。
      正确:static关键字声明的变量必须放在implementation外面,或者方法中,如果不为它赋值默认为0,
    4. 全局变量是不安全的,因为它可能会被外部修改,所以在定义全局变量时推荐使用static关键字修饰。
    5. 和const使用代替宏:如果使用static和const组合使用,不可以修改变量的值,否则编译器报错:
    // .h文件
    NSString *IsCanRun;
    @interface BenzCar : NSObject
    //NSString *name;// Cannot declare variable inside @interface or @protocol
    @end
    
    // .m文件
    @interface BenzCar ()
    //NSString *name;// Cannot declare variable inside @interface or @protocol
    @end
    
    NSString *BrandName; // Mercedes-Benz
    static NSString *EngineTechnology;
    @implementation BenzCar
    - (NSInteger) manufactureCar {
        
        static NSInteger allCarNum = 0;
        allCarNum ++;
        return allCarNum;
    }
    @end
    
    // 使用
    #import "BenzCar.h"
    
    IsCanRun = @"YES";
    
    extern NSString *BrandName;
    BrandName = @"Mercedes-Benz";
    
    // Undefined symbol: _EngineTechnology
    extern NSString *EngineTechnology;
    EngineTechnology = @"发动机核心技术";
    
    

    02 extern

    1. 想要访问全局变量可以使用extern关键字(extern修饰的全局变量默认是有外部链接的,作用域是整个工程,全局变量定义不能有static修饰)。
    2. 在一个文件内定义的全局变量,在另一个文件中,通过extern声明全局变量,就可以使用全局变量。OC常用场景,在.m文件中声明初始化全局变量,在.h文件使用extern对外扩展(一般只引用.h文件)。
    // .h文件
    extern NSString * const SEX_M;
    extern NSString * const SEX_F;
    @interface Person : NSObject
    @end
    
    // .m文件
    NSString * const SEX_M = @"male";
    NSString * const SEX_F = @"female";
    @implementation Person
    @end
    
    

    03 const

    1. 修饰常量
    2. 和static使用代替宏:如果使用static和const组合使用,不可以修改变量的值,否则编译器报错:
    3. const修饰基本数据类型和指针型数据类型的总结
    // const 修饰基本数据类型
    int const a = 100;
    const NSInteger b = 100;
    int  c = 101;
        
    a = 101;// Cannot assign to variable 'a' with const-qualified type 'const int'
    b = 101;// Cannot assign to variable 'b' with const-qualified type 'const NSInteger' (aka 'const long')
    a = c;// Cannot assign to variable 'b' with const-qualified type 'const NSInteger' (aka 'const long')
    b = c;// Cannot assign to variable 'b' with const-qualified type 'const NSInteger' (aka 'const long')
    
    
    // const 修饰基本数据指针类型
    int a1 = 1;
    int a2 = 2;
    int * const c1 = &a1;
    int const * c2 = &a1;
    const int * c3 = &a1;
    const int const * c4 = &a1;//Duplicate 'const' declaration specifier
    const int * const c5 = &a1;
    
    c1 = &a2;// Cannot assign to variable 'str1' with const-qualified type 'int *const'
    *c1 = 10;
    
    c2 = &a2;
    *c2 = 101;// Read-only variable is not assignable
    
    c3 = &a2;
    *c3 = 101;// Read-only variable is not assignable
    
    c4 = &a2;
    *c4 = 101;// Read-only variable is not assignable
    
    c5 = &a2;// Cannot assign to variable 'str1' with const-qualified type 'int *const'
    *c5 = 101;// Read-only variable is not assignable
    
    
    // const 修饰指针型数据类型
    NSString *b1 = @"";
    NSString *b2 = @"";
    NSString * const str1 = @"1";
    NSString const * str2 = @"2";
    const NSString * str3 = @"2";
    const NSString const * str4 = @"2";//Duplicate 'const' declaration specifier
    const NSString * const str5 = @"3";
    
    str1 = b2;// Cannot assign to variable 'str1' with const-qualified type 'NSString *const __strong'
    str1 = @"12";// Cannot assign to variable 'str1' with const-qualified type 'NSString *const __strong'
    
    str2 = b2;
    str2 = @"12";
    
    str3 = b2;
    str3 = @"12";
    
    str4 = b2;
    str4 = @"12";
    
    str5 = b2;// Cannot assign to variable 'str5' with const-qualified type 'const NSString *const __strong'
    str5 = @"12";// Cannot assign to variable 'str5' with const-qualified type 'const NSString *const __strong'
    
    
    // const 修饰可变指针型数据类型
    NSMutableString * const mstr1 = [@"12" mutableCopy];
    NSMutableString const * mstr2 = [@"12" mutableCopy];
    const NSMutableString * mstr3 = [@"12" mutableCopy];
    const NSMutableString const * mstr4 = [@"12" mutableCopy];// Duplicate 'const' declaration specifier
    const NSMutableString * const mstr5 = [@"12" mutableCopy];
    
    [mstr1 appendString:@"345"];
    mstr1 = [@"abc" mutableCopy];// Cannot assign to variable 'mstr1' with const-qualified type 'NSMutableString *const __strong'
    
    [mstr2 appendString:@"345"];
    mstr2 = [@"abc" mutableCopy];
    
    [mstr3 appendString:@"345"];
    mstr3 = [@"abc" mutableCopy];
    
    [mstr4 appendString:@"345"];
    mstr4 = [@"abc" mutableCopy];
    
    [mstr5 appendString:@"345"];
    mstr5 = [@"abc" mutableCopy];// Cannot assign to variable 'mstr5' with const-qualified type 'const NSMutableString *const __strong'
    
    【总结】:
    int const a = 100;
    不可以修改常量a的值
    const NSInteger b = 100;
    不可以修改常量b的值
    指针相关:const与*的位置,及const在*的左边还是右边
    int * const c1 = &a1;
    可以修改常量指针指向的原内存中的内容,常量指针不可以指向其他的内存
    int const * c2 = &a1;
    不可以修改常量指针指向的原内存中的内容,常量指针可以指向其他的内存
    NSString *const str1
    不可以修改常量指针指向的原内存中的内容,常量指针不可以指向其他的内存
    NSString const *str2"
    不可以修改常量指针指向的原内存中的内容,常量指针可以指向其他的内存
    NSMutableString const *mstr1
    可以修改常量指针指向的原内存中的内容,常量指针可以指向其他的内存
    NSMutableString *const mstr2
    可以修改常量指针指向的原内存中的内容,常量指针不可以指向其他的内存
    
    

    04 @property、@synthesize、@dynamic

    在正规的 Objective-C 编码风格中,存取方法有着严格的命名规范。 正因为有了这种严格的命名规范,所以 Objective-C 这门语言才能根据名称自动创建出存取方法。

    *完成属性定义后(@property(x, x, x,) classs var;ios6+),编译器会自动编写访问这些属性所需的方法,此过程叫做【自动合成(autosynthesis)】。【强调:这个过程由编译器在编译期执行,所以编辑器里看不到这些【合成方法(synthesized method】的源代码。】除了生成方法代码 getter/setter 之外,编译器还要自动向类中添加适当类型的【实例变量(var)】,并且在属性名【var】前面加下划线【】,以此作为实例变量的名字。

    我们每次在增加一个属性,系统都会在 ivar_list 中添加一个成员变量的描述,在 method_list 中增加 getter/setter 方法的描述,在属性列表中增加一个属性的描述,然后计算该属性在对象中的偏移量,然后给出 getter/setter 方法对应的实现,在 setter 方法中从偏移量的位置开始赋值,在 getter 方法中从偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转.

    @property的本质:@property = ivar(实例变量) + getter/setter(存取方法)
    @property有两个对应的词,即 @synthesize和 @dynamic。如果 @synthesize和 @dynamic都没写,那么默认的就是@syntheszie var = _var;

    @synthesize Xcode6以后省略, 默认在 .m的@implementation中添加这个@synthesize var = _var; 编译器期间,让编译器自动生成 getter/setter 方法;当有自定义的 getter/setter 方法时,会屏蔽自动生成该方法。

    1. 使用@synthesize 给属性添加【别名】后,将会覆盖自动合成的别名,只能使用新的别名。
    2. 在protocol中声明了属性(其实只有getter/setter方法,并没有属性实例),那么在使用它之前,需要使用@synthesize来合成实例变量。

    @dynamic Xcode6以后省略, 默认在.m的@implementation中添加这个@synthesize var; 告诉编译器,不自动生成 getter/setter 方法,避免编译期间产生警告,然后由自己实现存取方法或在运行时动态创建绑定存取方法。例如:一个属性被声明为 @dynamic var,而且实际没有提供 getter/setter 方法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = var 时,由于缺 getter 方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

    @interface Person : NSObject
    @property (nonatomic, copy) NSString *name;
    @end
    
    // 1
    @implementation Person
    - (void) printDes {
        NSLog(@" name = %@", _name);
    }
    @end
    
    // 2
    @implementation Person
    @synthesize name = name_New;// 别名
    - (void) printDes {
        NSLog(@" name = %@", _name);// Use of undeclared identifier '_name'
        NSLog(@" name = %@", name_New);
    }
    @end
    
    // 3
    @implementation Person
    @dynamic name;
    @end
    
    Person *p = [Person new];
    p.name = @"J.K.";// [Person setName:]: unrecognized selector sent to instance
    
    // 解决方案
    // 3.1 -  直接注释
    @implementation Person
    //@dynamic name;
    @end
    
    // 3.2 - 显式提供实例变量,手动添加 getter/setter 方法
    @interface Person ()
    {
        NSString *_name;
    }
    @end
    @implementation Person
    @dynamic name;
    - (void)setName:(NSString *)name {
        _name = [name copy];
        _name = name;
    }
    - (NSString *)name {
        return _name;
    }
    @end
    
    // 3.3 - 显式提供实例变量,通过runtime机制在运行时添加属性的存取方法.
    // 参考:在C函数中不能直接使用实例变量,需要将Objc对象self转成C中的结构体,
    //      因此在Person类同样需要显式声明实例变量而且访问级别是@public
    #import <objc/runtime.h>
    @interface Person ()
    {
        @public // 可注释
        NSString *_name;
    }
    @end
    @implementation Person
    @dynamic name;
    + (BOOL)resolveInstanceMethod:(SEL)sel {
        if (sel == @selector(setName:)) {
            class_addMethod([self class], sel, (IMP)setName, "v@:@");
            return YES;
        }else if (sel == @selector(name)){
            class_addMethod([self class], sel, (IMP)getName, "@@:");
            return YES;
        }
        return [super resolveInstanceMethod:sel];
    }
    void setName(id self, SEL _cmd, NSString* name)
    {
        if (((Person*)self)->_name != name) {
            ((Person *)self)->_name = [name copy]; // 点语法会导致死循环
        }
    }
    NSString* getName(id self, SEL _cmd)
    {
        return ((Person *)self)->_name; // 点语法会导致死循环
    }
    @end
    
    

    相关文章

      网友评论

          本文标题:ios 关键字

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