attribute是GNU C特點之一,在iOS用的比較普遍.系統中有許多地方使用到. attribute能夠設置函數屬性(Function Attribute )、變量屬性(Variable Attribute )和類型屬性(Type Attribute)等.ios
書寫格式:attribute後面會緊跟一對原括弧,括弧裏面是相應的attribute參數macos
__attribute__(xxx)
官方例子:NSLog網絡
#define NS_FORMAT_FUNCTION(F,A) __attribute__((format(__NSString__, F, A)))
format屬性能夠給被聲明的函數加上相似printf或者scanf的特徵,它可使編譯器檢查函數聲明和函數實際調用參數之間的格式化字符串是否匹配。該功能十分有用,尤爲是處理一些很難發現的bug。對於format參數的使用以下
format (archetype, string-index, first-to-check)
第一參數須要傳遞「archetype」指定是哪一種風格,這裏是 NSString;「string-index」指定傳入函數的第幾個參數是格式化字符串;「first-to-check」指定第一個可變參數所在的索引.框架
官方例子: abort() 和 exit()函數
該屬性通知編譯器函數從不返回值。當遇到相似函數還未運行到return語句就須要退出來的狀況,該屬性能夠避免出現錯誤信息。學習
官方例子:測試
- (CGSize)sizeWithFont:(UIFont *)font NS_DEPRECATED_IOS(2_0, 7_0, "Use -sizeWithAttributes:") __TVOS_PROHIBITED;
atom
//來看一下 後邊的宏
url
#define NS_DEPRECATED_IOS(_iosIntro, _iosDep, ...) CF_DEPRECATED_IOS(_iosIntro, _iosDep, __VA_ARGS__)
spa
define CF_DEPRECATED_IOS(_iosIntro, _iosDep, ...) __attribute__((availability(ios,introduced=_iosIntro,deprecated=_iosDep,message="" __VA_ARGS__)))
//宏展開之後以下
__attribute__((availability(ios,introduced=2_0,deprecated=7_0,message=""__VA_ARGS__)));
//ios便是iOS平臺
//introduced 從哪一個版本開始使用
//deprecated 從哪一個版本開始棄用
//message 警告的消息
availability屬性是一個以逗號爲分隔的參數列表,以平臺的名稱開始,包含一些放在附加信息裏的一些里程碑式的聲明。
introduced:第一次出現的版本。
deprecated:聲明要廢棄的版本,意味着用戶要遷移爲其餘API
obsoleted: 聲明移除的版本,意味着徹底移除,不再能使用它
unavailable:在這些平臺不可用
message:一些關於廢棄和移除的額外信息,clang發出警告的時候會提供這些信息,對用戶使用替代的API很是有用。
這個屬性支持的平臺:ios,macosx。
簡單例子:
//若是常常用,建議定義成相似系統的宏
- (void)oldMethod:(NSString *)string __attribute__((availability(ios,introduced=2_0,deprecated=7_0,message="用 -newMethod: 這個方法替代 "))){
NSLog(@"我是舊方法,不要調我");
}
- (void)newMethod:(NSString *)string{
NSLog(@"我是新方法");
}
效果:
Paste_Image.png
//若是調用了,會有警告
Paste_Image.png
告訴編譯器該方法不可用,若是強行調用編譯器會提示錯誤。好比某個類在構造的時候不想直接經過init來初始化,只能經過特定的初始化方法()好比單例,就能夠將init方法標記爲unavailable;
//系統的宏,能夠直接拿來用
#define UNAVAILABLE_ATTRIBUTE __attribute__((unavailable))
#define NS_UNAVAILABLE UNAVAILABLE_ATTRIBUTE
@interface Person : NSObject
@property(nonatomic,copy) NSString *name;
@property(nonatomic,assign) NSUInteger age;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithName:(NSString *)name age:(NSUInteger)age;
@end
Paste_Image.png
//實際上unavailable後面能夠跟參數,顯示一些信息,如:
//系統的
#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
表示這個類是一個根類(基類),好比NSObject,NSProxy.
//摘自系統
//NSProxy
NS_ROOT_CLASS
@interface NSProxy <NSObject> {
Class isa;
}
//NSObject
__OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0)
OBJC_ROOT_CLASS
OBJC_EXPORT
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
@property (nonatomic,strong) __attribute__((NSObject)) CFDictionaryRef myDictionary;
CFDictionaryRef屬於CoreFoundation框架的,也就是非OC對象,加上attribute((NSObject))後,myDictionary的內存管理會被當作OC對象來對待.
用來修飾類的designated initializer初始化方法,若是修飾的方法裏沒有調用super類的 designated initializer,編譯器會發出警告。能夠簡寫成NS_DESIGNATED_INITIALIZER
這篇文章講的很好,建議參考這個.
https://yq.aliyun.com/articles/5847
語法:
__attribute__((visibility("visibility_type")))
其中,visibility_type 是下列值之一:
default
假定的符號可見性可經過其餘選項進行更改。缺省可見性將覆蓋此類更改。缺省可見性與外部連接對應。
hidden
該符號不存放在動態符號表中,所以,其餘可執行文件或共享庫都沒法直接引用它。使用函數指針可進行間接引用。
internal
除非由 特定於處理器的應用二進制接口 (psABI) 指定,不然,內部可見性意味着不容許從另外一模塊調用該函數。
protected
該符號存放在動態符號表中,但定義模塊內的引用將與局部符號綁定。也就是說,另外一模塊沒法覆蓋該符號。
除指定 default 可見性外,此屬性均可與在這些狀況下具備外部連接的聲明結合使用。
您可在 C 和 C++ 中使用此屬性。在 C++ 中,還可將它應用於類型、成員函數和命名空間聲明。
系統用法:
// UIKIT_EXTERN extern
#ifdef __cplusplus
#define UIKIT_EXTERN extern "C" __attribute__((visibility ("default")))
#else
#define UIKIT_EXTERN extern __attribute__((visibility ("default")))
#endif
`
編譯器對函數參數進行NULL的檢查,參數類型必須是指針類型(包括對象)
//使用
- (int)addNum1:(int *)num1 num2:(int *)num2 __attribute__((nonnull (1,2))){//1,2表示第一個和第二個參數不能爲空
return *num1 + *num2;
}
- (NSString *)getHost:(NSURL *)url __attribute__((nonnull (1))){//第一個參數不能爲空
return url.host;
}
__attribute((aligned (n))),讓所做用的結構成員對齊在n字節天然邊界上。若是結構中有成員的長度大於n,則按照最大成員的長度來對齊.例如:
不加修飾的狀況
typedef struct
{
char member1;
int member2;
short member3;
}Family;
//輸出字節:
NSLog(@"Family size is %zd",sizeof(Family));
//輸出結果爲:
2016-07-25 10:28:45.380 Study[917:436064] Family size is 12
//修改字節對齊爲1
typedef struct
{
char member1;
int member2;
short member3;
}__attribute__ ((aligned (1))) Family;
//輸出字節:
NSLog(@"Family size is %zd",sizeof(Family));
//輸出結果爲:
2016-07-25 10:28:05.315 Study[914:435764] Family size is 12
和上面的結果一致,由於 設定的字節對齊爲1.而結構體中成員的最大字節數是int 4個字節,1 < 4,按照4字節對齊,和系統默認一致.
修改字節對齊爲8
typedef struct
{
char member1;
int member2;
short member3;
}__attribute__ ((aligned (8))) Family;
//輸出字節:
NSLog(@"Family size is %zd",sizeof(Family));
//輸出結果爲:
2016-07-25 10:28:05.315 Study[914:435764] Family size is 16
這裏 8 > 4,按照8字節對齊,結果爲16,不知道字節對齊的能夠看個人這篇文章http://www.jianshu.com/p/f69652c7df99
但是想了半天,也不知道這玩意有什麼用,設定值小於系統默認的,和沒設定同樣,設定大了,又浪費空間,效率也沒提升,感受學習學習就好.
讓指定的結構結構體按照一字節對齊,測試:
//不加packed修飾
typedef struct {
char version;
int16_t sid;
int32_t len;
int64_t time;
} Header;
//計算長度
NSLog(@"size is %zd",sizeof(Header));
輸出結果爲:
2016-07-22 11:53:47.728 Study[14378:5523450] size is 16
能夠看出,默認系統是按照4字節對齊
//加packed修飾
typedef struct {
char version;
int16_t sid;
int32_t len;
int64_t time;
}__attribute__ ((packed)) Header;
//計算長度
NSLog(@"size is %zd",sizeof(Header));
輸出結果爲:
2016-07-22 11:57:46.970 Study[14382:5524502] size is 15
用packed修飾後,變爲1字節對齊,這個經常使用於與協議有關的網絡傳輸中.