做一件事兒肯定是有原因,我來做這個(gè)事兒的原因,是因?yàn)槲淫i哥思考需要在沪编,路漫漫其修遠(yuǎn)兮呼盆,上下求索。
然后...鑫哥覺得蚁廓,要成為大牛访圃,首先要做的就是先跟大牛學(xué)習(xí)下,那么就抄一下大牛的代碼吧...(我覺得很對(duì))
一步一步走走看看相嵌,那么就先從我們最為常用的MJEX來入手腿时,我也來copy一遍代碼來試試
根據(jù)以前的樣子,那么我先把目錄寫下來饭宾,然后進(jìn)行一步一步一步的摩擦批糟,且來看看????
MJExtension
引入頭文件真的沒什么可說的
MJExtension.h作為一個(gè).h的頭文件引入類,可謂是清新脫俗看铆,簡(jiǎn)單明了 ...巴拉巴拉巴拉
然后下一步開始逐漸解析MJEX
MJExtensionConst
方法過期使用
#define MJExtensionDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)
這個(gè)方法在設(shè)計(jì)庫或者sdk的時(shí)候會(huì)使用到徽鼎,然后標(biāo)注顯示
具體使用的是如下方法
@property(nonatomic, copy)NSString *gdtype __attribute__((deprecated("已過期, 用goodsclassifytype替換")));
構(gòu)建錯(cuò)誤
#define MJExtensionBuildError(clazz, msg) \
NSError *error = [NSError errorWithDomain:msg code:250 userInfo:nil]; \
[clazz setMj_error:error];
其中,自定義錯(cuò)誤域?qū)ο驝ustomErrorDomain弹惦,通常用域名反寫否淤,也可以是任何其他字符串code錯(cuò)誤標(biāo)識(shí), 系統(tǒng)的code一般都大于零,自定code可以用枚舉(最好用負(fù)數(shù), 但不是必須的)userInfo自定義錯(cuò)誤信息棠隐,NSLocalizedDescriptionKey是NSError頭文件中預(yù)定義的鍵石抡,標(biāo)識(shí)錯(cuò)誤的本地化描述
可以通過NSError的localizedDescription方法獲得對(duì)應(yīng)的值信息
詳細(xì)介紹NSError的可以查看iphone跬步之--錯(cuò)誤信息 NSError
日志輸出
這一塊代碼沒什么可以講解的,就是log的打印
#ifdef DEBUG
#define MJExtensionLog(...) NSLog(__VA_ARGS__)
#else
#define MJExtensionLog(...)
#endif
使用
#define NSLog(fmt, ...) NSLog((@"%s [Line: %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
這個(gè)打印,會(huì)打印出你的類名方法名和對(duì)應(yīng)的行數(shù)[當(dāng)做平時(shí)的一個(gè)小知識(shí)來記憶吧~]
剩下的這一堆是斷言的使用
/**
* 斷言
* @param condition 條件
* @param returnValue 返回值
*/
#define MJExtensionAssertError(condition, returnValue, clazz, msg) \
[clazz setMj_error:nil]; \
if ((condition) == NO) { \
MJExtensionBuildError(clazz, msg); \
return returnValue;\
}
#define MJExtensionAssert2(condition, returnValue) \
if ((condition) == NO) return returnValue;
/**
* 斷言
* @param condition 條件
*/
#define MJExtensionAssert(condition) MJExtensionAssert2(condition, )
/**
* 斷言
* @param param 參數(shù)
* @param returnValue 返回值
*/
#define MJExtensionAssertParamNotNil2(param, returnValue) \
MJExtensionAssert2((param) != nil, returnValue)
/**
* 斷言
* @param param 參數(shù)
*/
#define MJExtensionAssertParamNotNil(param) MJExtensionAssertParamNotNil2(param, )```
>斷言:NSAssert()是一個(gè)宏助泽,用于開發(fā)階段調(diào)試程序中的Bug汁雷,通過為NSAssert()傳遞條件表達(dá)式來斷定是否屬于Bug,滿足條件返回真值报咳,程序繼續(xù)運(yùn)行侠讯,如果返回假值,則拋出異常暑刃,并且可以自定義異常描述厢漩。
這里引用下別人對(duì)于[斷言的介紹](http://www.reibang.com/p/6e444981ab45)
MJEX將打印所有的屬性使用宏定義在Const里面寫出,為了可以在全局中方便的調(diào)用
/**
- 打印所有的屬性
*/
define MJLogAllIvars \
-(NSString *)description
{
return [self mj_keyValues].description;
}
define MJExtensionLogAllProperties MJLogAllIvars
直接調(diào)用`MJLogAllIvars `的宏定義就可以直接輸出所有屬性
類屬性的使用
/**
- 類型(屬性類型)
*/
extern NSString *const MJPropertyTypeInt;
extern NSString *const MJPropertyTypeShort;
extern NSString *const MJPropertyTypeFloat;
extern NSString *const MJPropertyTypeDouble;
extern NSString *const MJPropertyTypeLong;
extern NSString *const MJPropertyTypeLongLong;
extern NSString *const MJPropertyTypeChar;
extern NSString *const MJPropertyTypeBOOL1;
extern NSString *const MJPropertyTypeBOOL2;
extern NSString *const MJPropertyTypePointer;
extern NSString *const MJPropertyTypeIvar;
extern NSString *const MJPropertyTypeMethod;
extern NSString *const MJPropertyTypeBlock;
extern NSString *const MJPropertyTypeClass;
extern NSString *const MJPropertyTypeSEL;
extern NSString *const MJPropertyTypeId;
從這個(gè)類屬性里面岩臣,我們可以清楚的了解到MJEX對(duì)于某些類的拓展使用
/**
- 成員變量類型(屬性類型)
*/
NSString *const MJPropertyTypeInt = @"i";
NSString *const MJPropertyTypeShort = @"s";
NSString *const MJPropertyTypeFloat = @"f";
NSString *const MJPropertyTypeDouble = @"d";
NSString *const MJPropertyTypeLong = @"l";
NSString *const MJPropertyTypeLongLong = @"q";
NSString *const MJPropertyTypeChar = @"c";
NSString *const MJPropertyTypeBOOL1 = @"c";
NSString *const MJPropertyTypeBOOL2 = @"b";
NSString const MJPropertyTypePointer = @"";
NSString *const MJPropertyTypeIvar = @"^{objc_ivar=}";
NSString *const MJPropertyTypeMethod = @"^{objc_method=}";
NSString *const MJPropertyTypeBlock = @"@?";
NSString *const MJPropertyTypeClass = @"#";
NSString *const MJPropertyTypeSEL = @":";
NSString *const MJPropertyTypeId = @"@";
【借鑒】對(duì)于.m里面的賦值溜嗜,從而借鑒可以從編輯全局的某些text或者Toast的信息可以使用上方式作為統(tǒng)一的管理:
例如
.h
`extern NSString *const MJToast_Success;`
.m
`NSString *const MJToast_Success = @"保存成功"`
從而在全局統(tǒng)一使用
##MJFoundation
繼承自`@interface MJFoundation : NSObject`只用一個(gè)方法
`+ (BOOL)isClassFromFoundation:(Class)c;`
>MJ是這樣注釋的----
集合中沒有NSObject,因?yàn)閹缀跛械念惗际抢^承自NSObject架谎,具體是不是NSObject需要特殊判斷
![使用NSSet將數(shù)據(jù)的不屬于NSObj的類加入.png](http://upload-images.jianshu.io/upload_images/693139-25f36e7cfb54e302.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
>【注意】NSSet和NSMutableSet是無序的!!!!看準(zhǔn)咯是無序的炸宵!因?yàn)樗旧淼呐判蚴鞘褂玫墓E判颍▌澲攸c(diǎn))
而且他是唯一的!谷扣!里面的每一個(gè)數(shù)據(jù)都是唯一的M寥I铀觥!9住(劃重點(diǎn))
之前我遇到的問題也是如此瑞凑,討厭于雙重for循環(huán)去去重,直接使用了NSMutableSet概页,但是沒有注意到是無序的序列籽御,對(duì)于需要排序的,建議寫一個(gè)字段排序的方法惰匙,這里不再做贅述
##MJProperty -- 包裝一個(gè)成員屬性
關(guān)于如何包裝一個(gè)成員屬性呢技掏,那么我們先看一下MJ如何去做的
`/** 成員屬性 */
@property (nonatomic, assign) objc_property_t property;`
> objc_property_t
···what is this?
[iOS反射機(jī)制: objc_property_t的使用](https://segmentfault.com/a/1190000004520289)
這為大哥寫的蠻詳細(xì)项鬼,這里做簡(jiǎn)略的介紹
`/// An opaque type that represents an Objective-C declared property.
typedef struct objc_property *objc_property_t;`
apple將其稱為一個(gè)隱藏的類型哑梳,OC中的一個(gè)聲明屬性。
>iOS屬性反射:說白了秃臣,就是將兩個(gè)對(duì)象的所有屬性涧衙,用動(dòng)態(tài)的方式取出來哪工,并根據(jù)屬性名奥此,自動(dòng)綁值。(注意:對(duì)象的類雁比,如果是派生類稚虎,就得靠其他方式來實(shí)現(xiàn)了,因?yàn)榈玫讲辉摶惖膶傩再松印#?
常用的反射方式蠢终,有如下兩種:
>2-從一個(gè)NSDictionary->自定義實(shí)體類(此方式最最常用,如網(wǎng)絡(luò)Json數(shù)據(jù)會(huì)組成NSDictionary茴她。sqlite查詢數(shù)據(jù)寻拂,可以用第三方組件組成NSDictionary)
直接上碼,(這里碼在NSObject類別中)
獲取對(duì)象所有屬性:
我注意到MJEX使用了這樣一個(gè)屬性---[關(guān)聯(lián)](http://blog.csdn.net/onlyou930/article/details/9299169)
![關(guān)聯(lián)屬性-MJEX.png](http://upload-images.jianshu.io/upload_images/693139-5f145a81a8f9ee75.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
這個(gè)類的核心代碼如下丈牢,我么一段一段進(jìn)行解析
// 通過字符串key創(chuàng)建對(duì)應(yīng)的keys
```objective-c
- (NSArray *)propertyKeysWithStringKey:(NSString *)stringKey
{
if (stringKey.length == 0) return nil;
NSMutableArray *propertyKeys = [NSMutableArray array];
// 如果有多級(jí)映射
NSArray *oldKeys = [stringKey componentsSeparatedByString:@"."];
for (NSString *oldKey in oldKeys) {
NSUInteger start = [oldKey rangeOfString:@"["].location;
if (start != NSNotFound) { // 有索引的key
NSString *prefixKey = [oldKey substringToIndex:start];
NSString *indexKey = prefixKey;
if (prefixKey.length) {
MJPropertyKey *propertyKey = [[MJPropertyKey alloc] init];
propertyKey.name = prefixKey;
[propertyKeys addObject:propertyKey];
indexKey = [oldKey stringByReplacingOccurrencesOfString:prefixKey withString:@""];
}
/** 解析索引 **/
// 元素
NSArray *cmps = [[indexKey stringByReplacingOccurrencesOfString:@"[" withString:@""] componentsSeparatedByString:@"]"];
for (NSInteger i = 0; i<cmps.count - 1; i++) {
MJPropertyKey *subPropertyKey = [[MJPropertyKey alloc] init];
subPropertyKey.type = MJPropertyKeyTypeArray;
subPropertyKey.name = cmps[i];
[propertyKeys addObject:subPropertyKey];
}
} else { // 沒有索引的key
MJPropertyKey *propertyKey = [[MJPropertyKey alloc] init];
propertyKey.name = oldKey;
[propertyKeys addObject:propertyKey];
}
}
return propertyKeys;
}
采用多級(jí)映射的方式祭钉,將對(duì)應(yīng)的關(guān)聯(lián)key值進(jìn)行