30天學會ios開發(fā)"4.類的介紹與使用"

類就好像設計圖,組裝出你的邏輯實體

類好比設計圖,根據類來實例化出可以使用的對象.
對象能承載類的設計功能,將你的邏輯具體實現.

//.h 聲明一個類
@interface SYBaseNavigationController : UINavigationController //表明這個類繼承自UINavigationController
//此處可以定義公有屬性
@end

//.m 實現這個類
@interface SYBaseNavigationController ()
//此處可以定義私有屬性
@end
@implementation SYBaseNavigationController
@end

1 所有的類皆繼承自父類NSObject,如果你要做一個工具類,你可以繼承自NSObject.
2 oc 只支持單繼承,所以你的父類只能有一個.

@implementation ViewController

- (void)viewDidLoad {
    NSLog(@"123");
    [super viewDidLoad];
    NSLog(@"456");
}

super 代表調用父類里的方法, 父類里也有一個viewDidLoad方法,此寫法表明要擴展父類的方法.擴展代碼寫的位置要根據實際情況來決定.

- (void)viewDidLoad {
    [super viewDidLoad];
    _view.backgroundColor = [UIColor purpleColor];
    [self.view addSubview:_vv];
}

屬性與懶加載

類的屬性訪問有兩種方式 一種是 _加上屬性名字的直接訪問方式,一種為self.加上屬性名的訪問方式,接下來說一下區(qū)別.
view 的訪問 與賦值方式直接對屬性奇效,而self.view 的讀取與賦值則會經過setter 和 getter 函數的處理.
getter 和setter 函數為oc 編譯代碼時默認生成,如果你不覆寫它們,那么"self." 和 "
"方式沒有任何區(qū)別.不過設想一個情景,如果我在讀取某屬性的時候想記錄一條日志,那么getter方法就很方便,比如

@implementation ViewController
@synthesize arr; //如果你需要getter 和 setter 都改的話需要這句,同時 _arr 訪問方式將無法再使用只能使用 arr 屬性,只能使用self.arr!!!!反之 如果只改 getter 和 setter 可以不用寫,同時 _arr 還能繼續(xù)使用
- (NSArray *)arr {
    NSLog(@"123"); //每次訪問數據我們就都能打出日志啦
    return arr;
}

- (void)setArr:(NSArray *)arr {
    arr = @[@"123"];
}

以下情況不需要@synthesize arr

@implementation ViewController
//@synthesize arr;

//- (NSArray *)arr {
//    NSLog(@"123");
//    return arr;
//}

- (void)setArr:(NSArray *)arr {
   NSLog (@"456")
    _arr =  @[@"123"]; // 這里是能繼續(xù)用_arr的
}

@implementation ViewController
//@synthesize arr;

- (NSArray *)arr {
    NSLog(@"123");
    return _arr;
}

//- (void)setArr:(NSArray *)arr {
//    _arr =  @[@"123"]; // 這里是能繼續(xù)用_arr的
//}


原則上建議都用"self."的方式,不過@"_"寫起來更快,就看你的個人喜好了.

懶加載則是靈活使用getter方法的一直方式,有時候你的屬性不確定在什么時候初始化好,那么就在第一次使用的時候初始化吧,懶加載的意思就是用到了再賦值,不用則永遠不會賦值! 懶加載能幫你減少內存占用,提升頁面加載的效率.

//標準的懶加載模板
- (NSArray *)arr {
    //self.arr 訪問時如果為空就會初始化,否則直接返回值,簡單而精妙,
    if (_arr==nil) {
        _arr = [NSArray new];
    }
    return arr;
}


如果你繼續(xù)使用_arr 方式訪問,懶加載是不會起效的哦~要用"self."

析構與構造

面向對象的設計如java php pychon 也包含OC 都有所謂的析構和構造函數,在類的誕生和消失時會被自動調用.

//每次你在打init的時候IDE會自動提示 
//構造函數
- (instancetype)init
{
    self = [super init];
    if (self) {
        <#statements#> //如果想在類初始化時做些動作,可以寫在這里哦
    }
    return self;
}

//析構函數
- (void)dealloc
{
    <#statements#> //析構函數不需要寫[super dealloc]
}


析構方法里經常會用來釋放資源句柄或者停止監(jiān)聽等操作,請不要忘記實現, 其后會反復提及此事!

category(類擴展)

category 在oc里有時又被稱為分類,不過這個詞不是能很好地反應他的功能,所以還是遵循英文的叫法.
category的主要作用為直接對類進行擴展,舉列子如F35戰(zhàn)斗機原本只有空對空導彈,你可以寫一個海軍用擴展那么F35就多了對艦導彈,也可以寫一個陸軍擴展多一個反坦克導彈.那么你用這個類的時候,直接就能對空對地對海了.哈哈
類的影響是在編譯階段就會開始的,所以擴展的方法一定要起好,務必添加獨一無二的前綴.


image.png
@interface F35AirFighter (ocean)
....
@implementation F35AirFighter (ocean)  //圓括號+分類名稱 你就定義了一個分類,不過你必須要有一個F35AirFighter的原始類.

1.分類是用于給原有類添加方法的,因為分類的結構體指針中,沒有屬性列表,只有方法列表。所以原則上講它只能添加方法, 不能添加屬性(成員變量),實際上可以通過其它方式添加屬性(接下來會說) ;
2.分類中的可以寫@property, 但不會生成setter/getter方法, 也不會生成實現以及私有的成員變量(編譯時會報警告);
3.可以在分類中訪問原有類中.h中的屬性;
4.如果分類中有和原有類同名的方法, 會優(yōu)先調用分類中的方法, 就是說會忽略原有類的方法。所以同名方法調用的優(yōu)先級為 分類 > 本類 > 父類。因此在開發(fā)中盡量不要覆蓋原有類;
5.如果多個分類中都有和原有類中同名的方法, 那么調用該方法的時候執(zhí)行誰由編譯器決定;編譯器會執(zhí)行最后一個參與編譯的分類中的方法。

來看看一個比較經典的UIVIew分類

.h
@interface UIView (Additions)
// Position of the top-left corner in superview's coordinates 此分類簡化了uiview 各屬性的訪問方式
@property CGPoint position;
@property CGFloat x;
@property CGFloat y;
@property CGFloat top;
@property CGFloat bottom;
@property CGFloat left;
@property CGFloat right;
.m
@implementation UIView (Additions)

- (CGFloat)x {
    return self.frame.origin.x;
}

- (void)setX:(CGFloat)x {
    CGRect rect = self.frame;
    rect.origin.x = x;
    [self setFrame:rect];
}

- (CGFloat)y {
    return self.frame.origin.y;
}

- (void)setY:(CGFloat)y {
    CGRect rect = self.frame;
    rect.origin.y = y;
    [self setFrame:rect];
}
....
使用時引入
#import "UIView+Additions.h"

這個category 向uivew 添加了 x,y 的屬性,這樣就不需要使用view.frame.origin.x 這樣繁瑣的訪問,直接x 和y 就可以了.不過有同學要提問了,不是說category 不能擴展屬性嗎, 其實根本原因是使用了系統沒有生成的setter/getter方法,可不可以在手動添加setter/getter來避免崩潰,完成調用呢? 其實是可以的。由于OC是動態(tài)語言,方法真正的實現是通過runtime完成的,雖然系統不給我們生成setter/getter,但我們可以通過runtime手動添加setter/getter方法。

#import <objc/runtime.h>

static NSString *nameWithSetterGetterKey = @"nameWithSetterGetterKey"; //定義一個key值
@implementation Programmer (Category)

//運行時實現setter方法

- (void)setNameWithSetterGetter:(NSString *)nameWithSetterGetter {
objc_setAssociatedObject(self, &nameWithSetterGetterKey, nameWithSetterGetter, OBJC_ASSOCIATION_COPY);
}

//運行時實現getter方法
- (NSString *)nameWithSetterGetter {
return objc_getAssociatedObject(self, &nameWithSetterGetterKey);
}

@end

programmer.nameWithSetterGetter = @"有setter/getter"; //調用setter,成功

NSLog(@"%@",programmer.nameWithSetterGetter); //調用getter,成功
// NSLog(@"%@",_nameWithSetterGetter); //這是調用_成員變量,錯誤提示為:(Use of undeclared identifier '_nameWithSetterGetter')

<objc/runtime.h> 為運行時所需要引入庫 OBJC_ASSOCIATION_COPY 等同于 copy 如果需要strong 使用OBJC_ASSOCIATION_RETAIN_NONATOMIC
static NSString *nameWithSetterGetterKey = @"nameWithSetterGetterKey"; //為定義的常量指針即可.
之前的uiview(addition)之所以x和y 都沒有定義key 是因為他們所需的值其實已經在frame.origin中了,所以 objc_setAssociatedObject / objc_getAssociatedObject只在值沒有存儲的載體時才需要使用,如果是快捷訪問方式這樣的擴展,你可以直接定義擴展方法和屬性.

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

相關閱讀更多精彩內容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,675評論 1 32
  • 把網上的一些結合自己面試時遇到的面試題總結了一下,以后有新的還會再加進來。 1. OC 的理解與特性 OC 作為一...
    AlaricMurray閱讀 2,669評論 0 20
  • 1.設計模式是什么? 你知道哪些設計模式,并簡要敘述?設計模式是一種編碼經驗,就是用比較成熟的邏輯去處理某一種類型...
    龍飝閱讀 2,303評論 0 12
  • 每日銀行必備的工作:查看最新財經政策資訊,盤點客戶資料,各種與客戶打交道,提醒著自己要在忙碌中度過,也許是為這機械...
    爪子小敏閱讀 181評論 0 0
  • 「今日早餐」 土司版快手蘋果派+牛奶 堅果+飯后一小時乳酸菌 下雨天,記得帶上你的好心情[愛心]
    桐嫲嫲閱讀 184評論 0 1

友情鏈接更多精彩內容