iOS 類別(分類)添加屬性

一:首先介紹Category好處:

1局雄、可以將類的實現(xiàn)分散到多個不同文件或多個不同框架中,方便代碼管理活尊。也可以對框架提供類的擴(kuò)展(因為框架類沒有源碼,不能修改)漏益。
2蛹锰、創(chuàng)建對私有方法的前向引用:如果其他類中的方法未實現(xiàn),在你訪問其他類的私有方法時編譯器報錯這時使用類別绰疤,在類別中聲明這些方法(不必提供方法實現(xiàn))铜犬,編譯器就不會再產(chǎn)生警告
3、向?qū)ο筇砑臃钦絽f(xié)議:創(chuàng)建一個NSObject的類別稱為“創(chuàng)建一個非正式協(xié)議”轻庆,因為可以作為任何類的委托對象使用癣猾。有兩個方面的局限性: (1)無法向類中添加新的實例變量,類別沒有位置容納實例變量余爆。(2)名稱沖突煎谍,即當(dāng)類別中的方法與原始類方法名稱沖突時,類別具有更高的優(yōu)先級龙屉。類別方法將完全取代初始方法從而無法再使用初始方法。這個類似于方法的重載,但是這里是直接覆蓋了原方法转捕。

二:Category只能添加方法作岖,而不能添加成員變量或?qū)傩?/h3>

我們知道在一個類中用@property聲明屬性,編譯器會自動幫我們生成成員變量和setter/getter五芝,但分類的指針結(jié)構(gòu)體中痘儡,根本沒有屬性列表。所以在分類中用@property聲明屬性枢步,既無法生成成員變量也無法生成setter/getter沉删。
因此:我們可以用@property聲明屬性,編譯會通過醉途,但run之后就會崩潰矾瑰。

三:如何添加?

既然報錯的根本原因是使用了系統(tǒng)沒有生成的setter/getter方法隘擎,可不可以在手動添加setter/getter來避免崩潰殴穴,完成調(diào)用呢?
其實是可以的货葬。由于OC是動態(tài)語言采幌,方法真正的實現(xiàn)是通過runtime完成的,雖然系統(tǒng)不給我們生成setter/getter震桶,但我們可以通過runtime手動添加setter/getter方法休傍。

(1)首先有一個類
.h文件
#import@interface Person : NSObject
@property (assign, nonatomic) NSInteger age;
-(void)run;
@end

.m文件
#import "Person.h"
@implementation Person
-(void)run{
    NSLog(@"%s",__func__);
}
@end
(2)添加類別
.h文件
#import "Person.h"
@interface Person (PersonExtention)
@property (copy, nonatomic) NSString *name;
-(void)saySex;
@end

.m文件
#import "Person+PersonExtention.h"
#import <objc/runtime.h>
@implementation Person (PersonExtention)
//定義常量 必須是C語言字符串
static char *PersonNameKey = "PersonNameKey";
-(void)setName:(NSString *)name{
    /*
    OBJC_ASSOCIATION_ASSIGN;            //assign策略
    OBJC_ASSOCIATION_COPY_NONATOMIC;    //copy策略
    OBJC_ASSOCIATION_RETAIN_NONATOMIC;  // retain策略

    OBJC_ASSOCIATION_RETAIN;
    OBJC_ASSOCIATION_COPY;
     */
     /*
     * id object 給哪個對象的屬性賦值
       const void *key 屬性對應(yīng)的key
       id value  設(shè)置屬性值為value
       objc_AssociationPolicy policy  使用的策略,是一個枚舉值蹲姐,和copy磨取,retain,assign是一樣的淤堵,手機(jī)開發(fā)一般都選擇NONATOMIC
          objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
     */

    objc_setAssociatedObject(self, PersonNameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
-(NSString *)name{
    return objc_getAssociatedObject(self, PersonNameKey);
}
-(void)saySex{
    NSLog(@"%s----%@",__func__,self);
}

@end

四:iOS分類不能添加屬性原因探索寝衫,

請參考:http://www.reibang.com/p/935142af6a47

五:疑問

有時候我們會看到如下現(xiàn)象:

屏幕快照 2017-10-16 上午11.56.12.png

這是為什么呢?

@property (nonatomic, assign) CGFloat x;

這里添加的屬性拐邪,實現(xiàn)我們在外部的調(diào)用慰毅,其實在這種情況下是不會自動生成實例變量的,我們只是通過重寫setter和getter方法來對self.frame進(jìn)行操作扎阶,并不是針對的我們聲明的比如x汹胃,我們使用的時候getter方法中返回的是 self.frame.origin.x

2.png

六:下面解釋一下屬性和成員變量的區(qū)別:

@property (nonatomic, strong) UIButton *myButton;

我們聲明了一個屬性,因為現(xiàn)在我們用的編譯器已經(jīng)是LLVM了,所以不再需要為屬性聲明實例變量了东臀。如果LLVM發(fā)現(xiàn)一個沒有匹配實例變量的屬性着饥,它將為你生成以下劃線開頭的實例變量_myButton,不需要自己手動再去寫實例變量惰赋。而且也不需要在.m文件中寫@synthesize myButton宰掉;也會自動為你生成setter呵哨,getter方法。@synthesize的作用就是讓編譯器為你自動生成setter與getter方法轨奄。那么在.m文件中可以直接的使用_myButton實例變量孟害,也可以通過屬性self.myButton兩者都是一樣的。
注意:
這里的self.myButton其實是調(diào)用的myButton屬性的getter/setter方法挪拟。
假如在Objective-C中我們這樣添加屬性聲明

@interface MyViewController:UIViewController
{
 NSString *name;
}
@end

.m文件中挨务,self.name 這樣的表達(dá)式是錯誤的。Xcode會提示你使用->,改成self->name就可以了玉组。因為oc中點表達(dá)式是表示調(diào)用方法谎柄,而上面的代碼中沒有name這個方法。

(1)Objective-C中的點語法說明:

如果點表達(dá)式出現(xiàn)在 "=" 左邊惯雳,該屬性名稱的setter方法將被調(diào)用朝巫。如果點表達(dá)式出現(xiàn)在右邊,該屬性名稱的getter方法將被調(diào)用吨凑。所以在oc中點表達(dá)式其實就是調(diào)用對象的settergetter方法的一種快捷方式捍歪。
@synthesize還有一個作用,可以指定與屬性對應(yīng)的實例變量鸵钝,例如@synthesize myButton = xxxx糙臼;那么self.myButton其實是操作的實例變量xxxx,而不是_myButton了恩商。

在實際項目中,我們一般在.m中這樣寫:@synthesize myButton;這樣寫了之后变逃,那么編譯器會自動生成myButton的實例變量,以及相應(yīng)的gettersetter方法怠堪。注意:_myButton這個實例變量是不存在的揽乱,因為自動生成的實例變量為myButton而不是_myButton,所以現(xiàn)在@synthesize的作用就相當(dāng)于指定實例變量粟矿;

如果.m文件中寫了@synthesize myButton;那么生成的實例變量就是myButton凰棉;如果沒寫@synthesize myButton;那么生成的實例變量就是_myButton。所以跟以前的用法還是有點細(xì)微的區(qū)別陌粹。

七:Category與Extension

匿名類別(匿名擴(kuò)展)是可以添加實例變量的
1撒犀、Extension的基本用法
Extension的創(chuàng)建方法與Category一樣,只要在原來選擇Category選擇Extension即可掏秩,比如我們?yōu)镻erson創(chuàng)建一個名為MyExtension的Extension或舞,則最終會生成一個Person_MyExtension.h文件:

//  Person_MyExtension.h

#import "Person.h"

@interface Person ()

@end

但要注意的是和Category不同的是它不會生成Person_MyExtension.m文件。之后我們可以在Person_MyExtension.h中直接添加成員變量蒙幻、屬性和方法映凳,如下:

//  Person_MyExtension.h

#import "Person.h"

@interface Person ()
{
    NSString * _address;
}
@property (nonatomic) NSInteger age;

-(NSString*)WhereAmI;

@end

他常用的形式不是創(chuàng)建一個單獨的文件,而是在實現(xiàn)文件中添加私有的成員變量邮破、屬性和方法诈豌。例如:

//  Person.m
#import "Person.h"

@interface Person ()
{
    NSString * _address;
}
@property (nonatomic) NSInteger age;

-(NSString*)WhereAmI;

@end

@implementation Person

-(NSString*)WhereAmI{
    return @"哪里";
}

@end

2仆救、Extension與Category區(qū)別

  • Extension
    • 在編譯器決議,是類的一部分队询,在編譯器和頭文件的@interface和實現(xiàn)文件里的@implement一起形成了一個完整的類派桩。
    • 伴隨著類的產(chǎn)生而產(chǎn)生,也隨著類的消失而消失蚌斩。
    • Extension一般用來隱藏類的私有消息,你必須有一個類的源碼才能添加一個類的Extension范嘱,所以對于系統(tǒng)一些類送膳,如NSString,就無法添加類擴(kuò)展
  • Category
    • 是運行期決議的
    • 類擴(kuò)展可以添加實例變量丑蛤,分類不能添加實例變量
      原因:因為在運行期叠聋,對象的內(nèi)存布局已經(jīng)確定,如果添加實例變量會破壞類的內(nèi)部布局受裹,這對編譯性語言是災(zāi)難性的碌补。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市棉饶,隨后出現(xiàn)的幾起案子厦章,更是在濱河造成了極大的恐慌,老刑警劉巖照藻,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件袜啃,死亡現(xiàn)場離奇詭異,居然都是意外死亡幸缕,警方通過查閱死者的電腦和手機(jī)群发,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來发乔,“玉大人熟妓,你說我怎么就攤上這事±干校” “怎么了起愈?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長抵栈。 經(jīng)常有香客問我告材,道長,這世上最難降的妖魔是什么古劲? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任斥赋,我火速辦了婚禮,結(jié)果婚禮上产艾,老公的妹妹穿的比我還像新娘疤剑。我一直安慰自己滑绒,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布隘膘。 她就那樣靜靜地躺著疑故,像睡著了一般。 火紅的嫁衣襯著肌膚如雪弯菊。 梳的紋絲不亂的頭發(fā)上纵势,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天,我揣著相機(jī)與錄音管钳,去河邊找鬼钦铁。 笑死,一個胖子當(dāng)著我的面吹牛才漆,可吹牛的內(nèi)容都是我干的牛曹。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼醇滥,長吁一口氣:“原來是場噩夢啊……” “哼黎比!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鸳玩,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤阅虫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后怀喉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體书妻,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年躬拢,在試婚紗的時候發(fā)現(xiàn)自己被綠了躲履。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡聊闯,死狀恐怖工猜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情菱蔬,我是刑警寧澤篷帅,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站拴泌,受9級特大地震影響魏身,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蚪腐,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一箭昵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧回季,春花似錦家制、人聲如沸正林。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽觅廓。三九已至,卻和暖如春涵但,著一層夾襖步出監(jiān)牢的瞬間杈绸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工矮瘟, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留蝇棉,地道東北人。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓芥永,卻偏偏與公主長得像,于是被迫代替她去往敵國和親钝吮。 傳聞我的和親對象是個殘疾皇子埋涧,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容