iOS OC 和Swift 成員變量 修飾符

現(xiàn)講一下屬性和成員兩變量的區(qū)別?好多人只知道@property (nonatomic,assign) NSInteger age;,其實(shí)property = getter + setter +ivar。一個(gè)getter方法,一個(gè)是setter方法,另外一個(gè)是成員變量,ivar就是成員變量。
我們定義2個(gè)property和幾個(gè)ivar,然后使用runtime取出來(lái)確認(rèn)一下他們的關(guān)系;
看代碼:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    unsigned int  count = 0;
    
    objc_property_t *propertyList = class_copyPropertyList([Person class], &count);
    for (int i  =0; i < count; i ++) {
        objc_property_t p = propertyList[i];
        NSLog(@" %s",property_getName(p));
    }
    free(propertyList);
    
    [self getAllIvarList];
    [self getAllMethodList];
    
}
- (void) getAllIvarList {
    unsigned int methodCount = 0;
    Ivar * ivars = class_copyIvarList([Person class], &methodCount);
    for (unsigned int i = 0; i < methodCount; i ++) {
        Ivar ivar = ivars[i];
        const char * name = ivar_getName(ivar);
        const char*type = ivar_getTypeEncoding(ivar);
        NSLog(@"成員變量的類(lèi)型為%s,名字為 %s ",type, name);
    }
    free(ivars);
}
- (void) getAllMethodList{
    unsigned int count = 0;
    Method *methods = class_copyMethodList([Person class], &count);
    for (int i = 0; i < count; i ++) {
        Method m = methods[i];
        SEL sel = method_getName(m);
        NSLog(@"method:%@",NSStringFromSelector(sel));
    }
}

然后在看一下輸出的參數(shù):

age
name
成員變量的類(lèi)型為@"NSString",名字為 publicName 
成員變量的類(lèi)型為@"NSString",名字為 privateName 
成員變量的類(lèi)型為@"NSString",名字為 protectedName 
成員變量的類(lèi)型為@"NSString",名字為 packageName 
成員變量的類(lèi)型為q,名字為 _age 
成員變量的類(lèi)型為@"NSString",名字為 _name 
method:initWithDic:
method:.cxx_destruct
method:name
method:setName:
method:init
method:setAge:
method:age
通過(guò)代碼驗(yàn)證可以知道的是定義的property都是成對(duì)出現(xiàn)的setter和getter方法,而成員變量則沒(méi)生成。

那么成員變量一般寫(xiě)在匿名類(lèi)里邊,然后.m文件內(nèi)容在外部無(wú)法訪問(wèn)的,造成了修飾符沒(méi)有起到作用。如下圖:
先看一下Objec-C:

#import "Person.h"

@interface Person ()
{
@public
    NSString *publicName;
@private
    NSString *privateName;
@protected
    NSString * protectedName;
    @package
    NSString *packageName;
}
@end

因?yàn)楸旧碓?m中,成員變量本身在外部就是訪問(wèn)不到的,用public修飾也沒(méi)用。

正確的是:

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Person : NSObject
{
@public
    NSString *publicName;
@private
    NSString *privateName;
@protected
    NSString * protectedName;
    @package
    NSString *packageName;
}

然后我們測(cè)試一下這4個(gè)層級(jí)的范圍:


4個(gè)層級(jí)的范圍

4個(gè)層級(jí)的范圍

可以看到編譯器直接報(bào)錯(cuò),private是僅僅當(dāng)前類(lèi)和類(lèi)別中可用,子類(lèi)都不能用,范圍最小。

protected

@protected 在外部不可以訪問(wèn),只能在子類(lèi)和自己類(lèi),類(lèi)別中訪問(wèn)。

public

@public @package在自己生成的framework外部可以訪問(wèn),和public類(lèi)似。
那么我們?cè)儆肒VC訪問(wèn)各個(gè)級(jí)別的看看能訪問(wèn)嗎?

初始化Person

- (instancetype)init{
    self = [super init];
    if (self) {
        self->privateName = @"privateName";
        self->protectedName = @"protectedName";
        self->packageName = @"packageName";
        self->publicName = @"publicName";
    }
    return self;
}

通過(guò)KVC訪問(wèn)成員變量:


KVC
使用KVC訪問(wèn)framework中的成員變量測(cè)試:
framework
經(jīng)過(guò)測(cè)試私有和受保護(hù)的使用KVC也可以訪問(wèn)和賦值的,其實(shí)系統(tǒng)中有些成員變量我們也可以沖過(guò)使用這個(gè)方式來(lái)訪問(wèn)。
其實(shí)根據(jù)測(cè)試,OC類(lèi)中和子類(lèi)KVC都可訪問(wèn)所有成員變量。

測(cè)試版本:Xcode 10.2.1

@private私有的
代表私有,也就是只有自己有,別人誰(shuí)都不可用,不不可以繼承的。

@protected受保護(hù)的
相較上邊的private而言,就沒(méi)有那么自私了,他自己可以用,自己的子類(lèi)也是可以共享的,是可以繼承的.

@public公共的
相較上邊而言,誰(shuí)都可以用,只要你有這個(gè)類(lèi)的對(duì)象,就可以拿到public下的變量,

@package包
這個(gè)主要是用于框架類(lèi),使用@private太限制,使用@protected或者@public又太開(kāi)放,就使用這個(gè)package吧。

那么我們?cè)诳匆幌耂wift 5.0:
private

訪問(wèn)級(jí)別所修飾的屬性或者方法只能在當(dāng)前類(lèi)里訪問(wèn)

fileprivate

訪問(wèn)級(jí)別所修飾的屬性或者方法在當(dāng)前的 Swift 源文件里可以訪問(wèn)

internal

訪問(wèn)級(jí)別所修飾的屬性或方法在源代碼所在的整個(gè)模塊都可以訪問(wèn)
如果是框架或者庫(kù)代碼,則在整個(gè)框架內(nèi)部都可以訪問(wèn),框架由外部代碼所引用時(shí),則不可以訪問(wèn)

public

可以被任何人訪問(wèn)。但其他 module 中不可以被 override 和繼承,而在 module 內(nèi)可以被 override 和繼承

open

可以被任何人使用,包括 override 和繼承

從高到低排序如下:

open > public > interal > fileprivate > private

Swift測(cè)試代碼:

import Foundation
class Car: NSObject {
    var name = "car_name"
    private var privateName = "privateName"
    public var publicName = "publicName"
    fileprivate var fileprivateName = "fileprivateName"
    open var openName = "openName"
}
class Car2: Car {
    override init() {
        super.init()
        self.name = ""
        self.publicName = ""
        self.fileprivateName = ""
        self.openName = ""
===============本行報(bào)錯(cuò) ===============
        self.privateName = ""
    }
    func loadCar() -> Void {
        let car = Car()
        car.fileprivateName = ""
        car.publicName = ""
        car.name = ""
        car.openName = ""
    }
}
image.png

然后使用swift制作framework之后測(cè)試如下:
測(cè)試打包前源代碼:

open class Car: NSObject {
    var name = "car_name"
    private var privateName = "privateName"
    public var publicName = "publicName"
    fileprivate var fileprivateName = "fileprivateName"
    open var openName = "openName"
    
    open func work() -> Void{
        print("car work")
    }
    public func publicWork() -> Void{
        print("car publicwork")
    }
}
public class Car2: Car {
    override init() {
        super.init()
        self.name = ""
        self.publicName = ""
        self.fileprivateName = ""
        self.openName = ""
//        self.privateName = ""
    }
    override public func work() {
        
    }
    override public func publicWork() {
        
    }
    func loadCar() -> Void {
        let car = Car()
        car.fileprivateName = ""
        car.publicName = ""
        car.name = ""
        car.openName = ""
    }
}
open and public

編譯之前:

    var name = "car_name"
    private var privateName = "privateName"
    public var publicName = "publicName"
    fileprivate var fileprivateName = "fileprivateName"
    open var openName = "openName"

編譯之后:

open class Car : NSObject {

    public var publicName: String

    open var openName: String

    open func work()

    public func publicWork()
}

打包成framework,則public和open 修飾的屬性可見(jiàn),其他的則不在model中。

參考文檔:
官方文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容