運(yùn)行時(shí)是一個(gè)好東西,他可以幫助我們解決很多的問(wèn)題.在平時(shí)的開(kāi)發(fā)中可能用的不是很多.但是做為APP開(kāi)發(fā)人員遇到的崩潰情況肯定很多了.大致分為兩類 ?一類是由于代碼不嚴(yán)謹(jǐn)導(dǎo)致的數(shù)組越界 ? 一類是對(duì)字符串為空的情況下沒(méi)有判斷. ?這是本人遇到最多的崩潰情況了.解決好這個(gè)兩個(gè),基本上APP就不會(huì)崩潰.那么那么多的對(duì)數(shù)組操作以及字符串操作一個(gè)一個(gè)做判斷嗎? ? ?當(dāng)然這是我們應(yīng)該做的,但是也有更好的以及方便的處理方式
提醒一下:
1毁嗦、不要過(guò)分相信服務(wù)器返回的數(shù)據(jù)會(huì)永遠(yuǎn)的正確啥么。
2、在對(duì)數(shù)據(jù)處理上,要進(jìn)行容錯(cuò)處理泛豪,進(jìn)行相應(yīng)判斷之后再處理數(shù)據(jù)蚜迅,這是一個(gè)良好的編程習(xí)慣。
3.老板讓你明天上線,你還沒(méi)有做容錯(cuò)處理.所謂閻王叫你三更死......都是累,淚........
主要技術(shù)點(diǎn):
運(yùn)行時(shí):導(dǎo)入框架
```
#import <objc/runtime.h>
```
這里主要通過(guò)runtime的method swizzling 交換方法的實(shí)現(xiàn) 提前判斷方法的參數(shù)是否符合要求 ? 在創(chuàng)建創(chuàng)建類當(dāng)中的load方法里面利用單例交換數(shù)組字典等方法,替換成自己的方法,方便對(duì)參數(shù)做出相應(yīng)的處理 .打個(gè)比方,檢測(cè)到參數(shù)為nil的時(shí)候直接return ? .就有效的防止了崩潰
```
+ (void)swizzleInstanceMethodWithClass:(Class)class
originalSelector:(SEL)originalSelector
swizzledMethod:(SEL)swizzledSelector {
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
if (class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) {
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//? ? ? ? NSArray
[self swizzleInstanceMethodWithClass:NSClassFromString(@"__NSArrayI") originalSelector:@selector(objectAtIndex:) swizzledMethod:@selector(fcx_safeObjectAtIndex:)];
//? ? ? ? NSMutableArray
[self swizzleInstanceMethodWithClass:NSClassFromString(@"__NSArrayM") originalSelector:@selector(objectAtIndex:) swizzledMethod:@selector(fcx_safeObjectAtIndex:)];
//? ? ? ? [self swizzleInstanceMethodWithClass:NSClassFromString(@"__NSArrayM") originalSelector:@selector(addObject:) swizzledMethod:@selector(fcx_safeAddObject:)];
[self swizzleInstanceMethodWithClass:NSClassFromString(@"__NSArrayM") originalSelector:@selector(replaceObjectAtIndex:withObject:) swizzledMethod:@selector(fcx_safeReplaceObjectAtIndex:withObject:)];
[self swizzleInstanceMethodWithClass:NSClassFromString(@"__NSArrayM") originalSelector:@selector(insertObject:atIndex:) swizzledMethod:@selector(fcx_safeInsertObject:atIndex:)];
//? ? ? ? NSDictionary
//? ? ? ? [self swizzleClassMethodWithClass:[NSDictionary class] originalSelector:@selector(dictionaryWithObjects:forKeys:count:) swizzledMethod:@selector(fcx_safeDictionaryWithObjects:forKeys:count:)];
//? ? ? ? NSMutableDictionary
[self swizzleInstanceMethodWithClass:NSClassFromString(@"__NSDictionaryM") originalSelector:@selector(setObject:forKey:) swizzledMethod:@selector(fcx_safeSetObject:forKey:)];
});
}
```
這里對(duì)字典賦值進(jìn)行一個(gè)講解,大家可以舉一反三去思考.后面會(huì)直接提供代碼.
在前面的單例中我們已經(jīng)利用swizzling 將setObject:forKey: 這個(gè)方法替換成了我們自己的方法(fcx_safeSetObject:forKey:
[self swizzleInstanceMethodWithClass:NSClassFromString(@"__NSDictionaryM") originalSelector:@selector(setObject:forKey:) swizzledMethod:@selector(fcx_safeSetObject:forKey:)];
//替換之后的方法 ? 通俗講就是我們利用對(duì)字段賦值的時(shí)候會(huì)直接調(diào)用下面的方法
```
- (void)fcx_safeSetObject:(id)anObject forKey:(id)aKey {
//如果字典的key值為空則 return ??
if (!aKey)
{
FCXSCLOG(@"[%@ %@] nil key. key cannot be nil", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
return;
}
//如果字典的key值為空則 return
if (!anObject)
{
FCXSCLOG(@"[%@ %@] nil object. object cannot be nil", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
return;
}
[self fcx_safeSetObject:anObject forKey:aKey];
}
```
當(dāng)然各位也可以根據(jù)自己的需求進(jìn)行相應(yīng)的處理.下面是源碼.供大家參考 ??
//溫馨提示直接創(chuàng)建一個(gè)FCXSafeCollection類 ?然后將下面代碼全部粘貼到.m文件拖動(dòng)工程即可
```
#import "FCXSafeCollection.h"
#import
#if DEBUG
#defineFCXSCLOG(...) fcxSafeCollectionLog(__VA_ARGS__)
#else
#defineFCXSCLOG(...)
#endif
voidfcxSafeCollectionLog(NSString *fmt, ...) NS_FORMAT_FUNCTION(1, 2);
voidfcxSafeCollectionLog(NSString *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
NSString *content = [[NSString alloc] initWithFormat:fmtarguments:ap];
NSLog(@"***Terminating app due touncaught exception\n");
NSLog(@"***reason:-%@", content);
va_end(ap);
NSLog(@"*** First throw callstack:\n%@", [NSThread callStackSymbols]);
}
#pragmamark - NSArray
@interfaceNSArray (Safte)
@end
@implementationNSArray (Safte)
- (id)fcx_safeObjectAtIndex:(NSUInteger)index{
if (self.count > index) {
return [self fcx_safeObjectAtIndex:index];
}else {
FCXSCLOG(@"[%@ %@] index %lubeyond bounds [0 .. %lu]",
NSStringFromClass([selfclass]),
NSStringFromSelector(_cmd),
(unsigned long)index,
MAX((unsigned long)self.count- 1, 0));
return nil;
}
}
@end
//**************************************************************
#pragmamark - NSMutableArray
@interfaceNSMutableArray (Safte)
@end
@implementationNSMutableArray (Safte)
- (id)fcx_safeObjectAtIndex:(NSUInteger)index{
if (self.count > index) {
return [self fcx_safeObjectAtIndex:index];
}else {
FCXSCLOG(@"[%@ %@] index %lubeyond bounds [0 .. %lu]",
NSStringFromClass([selfclass]),
NSStringFromSelector(_cmd),
(unsigned long)index,
MAX((unsigned long)self.count - 1, 0));
return nil;
}
}
- (void)fcx_safeAddObject:(id)anObject{
if (anObject) {
[self fcx_safeAddObject:anObject];
}else {
FCXSCLOG(@"[%@ %@], nil object.object cannot be nil", NSStringFromClass([self class]),NSStringFromSelector(_cmd));
}
}
- (void)fcx_safeReplaceObjectAtIndex:(NSUInteger)indexwithObject:(id)anObject {
if (index >= self.count) {
FCXSCLOG(@"[%@ %@] index %lubeyond bounds [0 .. %lu].",
NSStringFromClass([selfclass]),
NSStringFromSelector(_cmd),
(unsigned long)index,
MAX((unsigned long)self.count- 1, 0));
return;
}else if (!anObject) {
FCXSCLOG(@"[%@ %@] nil object.object cannot be nil", NSStringFromClass([self class]),NSStringFromSelector(_cmd));
return;
}
[self fcx_safeReplaceObjectAtIndex:index withObject:anObject];
}
- (void)fcx_safeInsertObject:(id)anObjectatIndex:(NSUInteger)index {
if (index > self.count)
{
FCXSCLOG(@"[%@ %@] index %lubeyond bounds [0...%lu].",
NSStringFromClass([selfclass]),
NSStringFromSelector(_cmd),
(unsigned long)index,
MAX((unsigned long)self.count- 1, 0));
return;
}
if (!anObject)
{
FCXSCLOG(@"[%@ %@] nil object.object cannot be nil", NSStringFromClass([self class]),NSStringFromSelector(_cmd));
return;
}
[self fcx_safeInsertObject:anObject atIndex:index];
}
@end
//**************************************************************
#pragmamark - NSDictionary
@interfaceNSDictionary (Safte)
@end
@implementationNSDictionary (Safte)
+ (instancetype)fcx_safeDictionaryWithObjects:(constid_Nonnull __unsafe_unretained*)objects forKeys:(const id_Nonnull __unsafe_unretained *)keys count:(NSUInteger)cnt {
id validObjects[cnt];
id validKeys[cnt];
NSUInteger count = 0;
for (NSUInteger i = 0; i < cnt; i++)
{
if (objects[i] && keys[i])
{
validObjects[count] = objects[i];
validKeys[count] = keys[i];
count ++;
}
else
{
FCXSCLOG(@"[%@ %@] NIL objector key at index{%lu}.",
NSStringFromClass(self),
NSStringFromSelector(_cmd),
(unsigned long)i);
}
}
return [self fcx_safeDictionaryWithObjects:validObjectsforKeys:validKeys count:count];
}
@end
//**************************************************************
#pragmamark - NSMuatbleDictionary
@interfaceNSMutableDictionary (Safte)
@end
@implementationNSMutableDictionary (Safte)
- (void)fcx_safeSetObject:(id)anObjectforKey:(id)aKey {
if (!aKey)
{
FCXSCLOG(@"[%@ %@] nil key. keycannot be nil", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
return;
}
if (!anObject)
{
FCXSCLOG(@"[%@ %@] nil object.object cannot be nil", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
return;
}
[self fcx_safeSetObject:anObject forKey:aKey];
}
@end
//**************************************************************
@implementationFCXSafeCollection
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//NSArray
[self swizzleInstanceMethodWithClass:NSClassFromString(@"__NSArrayI")originalSelector:@selector(objectAtIndex:) swizzledMethod:@selector(fcx_safeObjectAtIndex:)];
//NSMutableArray
[self swizzleInstanceMethodWithClass:NSClassFromString(@"__NSArrayM")originalSelector:@selector(objectAtIndex:) swizzledMethod:@selector(fcx_safeObjectAtIndex:)];
//[selfswizzleInstanceMethodWithClass:NSClassFromString(@"__NSArrayM")originalSelector:@selector(addObject:)swizzledMethod:@selector(fcx_safeAddObject:)];
[self swizzleInstanceMethodWithClass:NSClassFromString(@"__NSArrayM")originalSelector:@selector(replaceObjectAtIndex:withObject:) swizzledMethod:@selector(fcx_safeReplaceObjectAtIndex:withObject:)];
[self swizzleInstanceMethodWithClass:NSClassFromString(@"__NSArrayM")originalSelector:@selector(insertObject:atIndex:) swizzledMethod:@selector(fcx_safeInsertObject:atIndex:)];
//NSDictionary
//[selfswizzleClassMethodWithClass:[NSDictionary class]originalSelector:@selector(dictionaryWithObjects:forKeys:count:)swizzledMethod:@selector(fcx_safeDictionaryWithObjects:forKeys:count:)];
//NSMutableDictionary
[selfswizzleInstanceMethodWithClass:NSClassFromString(@"__NSDictionaryM") originalSelector:@selector(setObject:forKey:)swizzledMethod:@selector(fcx_safeSetObject:forKey:)];
});
}
+ (void)swizzleInstanceMethodWithClass:(Class)class
originalSelector:(SEL)originalSelector
swizzledMethod:(SEL)swizzledSelector{
Method originalMethod = class_getInstanceMethod(class,originalSelector);
Method swizzledMethod = class_getInstanceMethod(class,swizzledSelector);
if (class_addMethod(class,originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))){
class_replaceMethod(class,swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}else {
method_exchangeImplementations(originalMethod,swizzledMethod);
}
}
+ (void)swizzleClassMethodWithClass:(Class)class
originalSelector:(SEL)originalSelector
swizzledMethod:(SEL)swizzledSelector{
Method originalMethod = class_getClassMethod(class,originalSelector);
Method swizzledMethod = class_getClassMethod(class,swizzledSelector);
//if (class_addMethod(class, originalSelector,method_getImplementation(swizzledMethod),method_getTypeEncoding(swizzledMethod))) {
//
//class_replaceMethod(class, swizzledSelector,method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
//}else {
//
method_exchangeImplementations(originalMethod,swizzledMethod);
//}
}
@end
#pragmamark - KeyValueSafeCollections
@interfaceNSObject (FCXKeyValueSafeCollections)
@end
@implementationNSObject (FCXKeyValueSafeCollections)
//當(dāng)對(duì)一個(gè)非類對(duì)象屬性設(shè)置nil時(shí)诬乞,就會(huì)執(zhí)行setNilValueForKey:方法,setNilValueForKey:方法的默認(rèn)實(shí)現(xiàn),是產(chǎn)生一個(gè)NSInvalidArgumentException的異常,但是你可以重寫(xiě)這個(gè)方法.
- (void)setNilValueForKey:(NSString*)key {
FCXSCLOG(@"[%@ %@]: could not set nilas the value for the key %@.", NSStringFromClass([self class]),NSStringFromSelector(_cmd), key);
}
```
//如果沒(méi)有對(duì)應(yīng)的訪問(wèn)器方法(setter方法),如果接受者的類的+accessInstanceVariablesDirectly方法返回YES,那么就查找這個(gè)接受者的與key相匹配的實(shí)例變量(匹配模式為_(kāi),_is,,is):比如:key為age,只要屬性存在_age,_isAge,age,isAge中的其中一個(gè)就認(rèn)為匹配上了,如果找到這樣的一個(gè)實(shí)例變量,并且的類型是一個(gè)對(duì)象指針類型,首先released對(duì)象上的舊值,然后把傳入的新值retain后的傳入的值賦值該成員變量,如果方法的參數(shù)類型是NSNumber或NSValue的對(duì)應(yīng)的基本類型,先把它轉(zhuǎn)換為基本數(shù)據(jù)類,再執(zhí)行方法,傳入轉(zhuǎn)換后的數(shù)據(jù).
//+(BOOL)accessInstanceVariablesDirectly {
//return YES;
//}
//對(duì)于數(shù)據(jù)模型中缺少的册赛、不能與任何鍵配對(duì)的屬性的時(shí)候钠导,系統(tǒng)會(huì)自動(dòng)調(diào)用setValue:forUndefinedKey:這個(gè)方法,該方法默認(rèn)的實(shí)現(xiàn)會(huì)引發(fā)一個(gè)NSUndefinedKeyExceptiony異常,但是我們可以重寫(xiě)setValue:forUndefinedKey:方法讓程序在運(yùn)行過(guò)程中不引發(fā)任何異常信息且正常工作
- (void)setValue:(id)valueforUndefinedKey:(NSString *)key {
FCXSCLOG(@"[%@ %@]: this class is notkey value coding-compliant for the key %@.", NSStringFromClass([selfclass]), NSStringFromSelector(_cmd), key);
}
//通過(guò)valueForKey獲取對(duì)象屬性值的方法時(shí)森瘪,如果代碼中的key值不存在牡属,系統(tǒng)會(huì)自動(dòng)調(diào)用valueForUndefinedKey:這個(gè)方法,該方法默認(rèn)的實(shí)現(xiàn)會(huì)引發(fā)一個(gè)NSUndefinedKeyExceptiony異常,但是我們可以重寫(xiě)valueForUndefinedKey:方法讓程序在運(yùn)行過(guò)程中不引發(fā)任何異常信息且正常工作
/**
*通過(guò)valueForKey獲取對(duì)象屬性值的方法時(shí)扼睬,如果代碼中的key值不存在逮栅,系統(tǒng)會(huì)自動(dòng)調(diào)用valueForUndefinedKey:這個(gè)方法,該方法默認(rèn)的實(shí)現(xiàn)會(huì)引發(fā)一個(gè)NSUndefinedKeyExceptiony異常,但是我們可以重寫(xiě)valueForUndefinedKey:方法讓程序在運(yùn)行過(guò)程中不引發(fā)任何異常信息且正常工作
*
*@return nil
*
*@notice雖然這步可以返回nil不閃退痰驱,但是后續(xù)操作依然可能有問(wèn)題
*/
- (id)valueForUndefinedKey:(NSString*)key {
FCXSCLOG(@"[%@ %@]: this class is notkey value coding-compliant for the key %@.", NSStringFromClass([selfclass]), NSStringFromSelector(_cmd), key);
return nil;
}
@end
有問(wèn)題+QQ648731281 ?歡迎騷擾 ? 相互交流學(xué)習(xí)