運行時是一個好東西,他可以幫助我們解決很多的問題.在平時的開發中可能用的不是很多.但是做為APP開發人員遇到的崩潰情況肯定很多了.大致分為兩類 ?一類是由于代碼不嚴謹導致的數組越界 ? 一類是對字符串為空的情況下沒有判斷. ?這是本人遇到最多的崩潰情況了.解決好這個兩個,基本上APP就不會崩潰.那么那么多的對數組操作以及字符串操作一個一個做判斷嗎? ? ?當然這是我們應該做的,但是也有更好的以及方便的處理方式
提醒一下:
1、不要過分相信服務器返回的數據會永遠的正確。
2、在對數據處理上,要進行容錯處理,進行相應判斷之后再處理數據,這是一個良好的編程習慣。
3.老板讓你明天上線,你還沒有做容錯處理.所謂閻王叫你三更死......都是累,淚........
主要技術點:
運行時:導入框架
```
#import <objc/runtime.h>
```
這里主要通過runtime的method swizzling 交換方法的實現 提前判斷方法的參數是否符合要求 ? 在創建創建類當中的load方法里面利用單例交換數組字典等方法,替換成自己的方法,方便對參數做出相應的處理 .打個比方,檢測到參數為nil的時候直接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:)];
});
}
```
這里對字典賦值進行一個講解,大家可以舉一反三去思考.后面會直接提供代碼.
在前面的單例中我們已經利用swizzling 將setObject:forKey: 這個方法替換成了我們自己的方法(fcx_safeSetObject:forKey:
[self swizzleInstanceMethodWithClass:NSClassFromString(@"__NSDictionaryM") originalSelector:@selector(setObject:forKey:) swizzledMethod:@selector(fcx_safeSetObject:forKey:)];
//替換之后的方法 ? 通俗講就是我們利用對字段賦值的時候會直接調用下面的方法
```
- (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];
}
```
當然各位也可以根據自己的需求進行相應的處理.下面是源碼.供大家參考 ??
//溫馨提示直接創建一個FCXSafeCollection類 ?然后將下面代碼全部粘貼到.m文件拖動工程即可
```
#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)
//當對一個非類對象屬性設置nil時,就會執行setNilValueForKey:方法,setNilValueForKey:方法的默認實現,是產生一個NSInvalidArgumentException的異常,但是你可以重寫這個方法.
- (void)setNilValueForKey:(NSString*)key {
FCXSCLOG(@"[%@ %@]: could not set nilas the value for the key %@.", NSStringFromClass([self class]),NSStringFromSelector(_cmd), key);
}
```
//如果沒有對應的訪問器方法(setter方法),如果接受者的類的+accessInstanceVariablesDirectly方法返回YES,那么就查找這個接受者的與key相匹配的實例變量(匹配模式為_,_is,,is):比如:key為age,只要屬性存在_age,_isAge,age,isAge中的其中一個就認為匹配上了,如果找到這樣的一個實例變量,并且的類型是一個對象指針類型,首先released對象上的舊值,然后把傳入的新值retain后的傳入的值賦值該成員變量,如果方法的參數類型是NSNumber或NSValue的對應的基本類型,先把它轉換為基本數據類,再執行方法,傳入轉換后的數據.
//+(BOOL)accessInstanceVariablesDirectly {
//return YES;
//}
//對于數據模型中缺少的、不能與任何鍵配對的屬性的時候,系統會自動調用setValue:forUndefinedKey:這個方法,該方法默認的實現會引發一個NSUndefinedKeyExceptiony異常,但是我們可以重寫setValue:forUndefinedKey:方法讓程序在運行過程中不引發任何異常信息且正常工作
- (void)setValue:(id)valueforUndefinedKey:(NSString *)key {
FCXSCLOG(@"[%@ %@]: this class is notkey value coding-compliant for the key %@.", NSStringFromClass([selfclass]), NSStringFromSelector(_cmd), key);
}
//通過valueForKey獲取對象屬性值的方法時,如果代碼中的key值不存在,系統會自動調用valueForUndefinedKey:這個方法,該方法默認的實現會引發一個NSUndefinedKeyExceptiony異常,但是我們可以重寫valueForUndefinedKey:方法讓程序在運行過程中不引發任何異常信息且正常工作
/**
*通過valueForKey獲取對象屬性值的方法時,如果代碼中的key值不存在,系統會自動調用valueForUndefinedKey:這個方法,該方法默認的實現會引發一個NSUndefinedKeyExceptiony異常,但是我們可以重寫valueForUndefinedKey:方法讓程序在運行過程中不引發任何異常信息且正常工作
*
*@return nil
*
*@notice雖然這步可以返回nil不閃退,但是后續操作依然可能有問題
*/
- (id)valueForUndefinedKey:(NSString*)key {
FCXSCLOG(@"[%@ %@]: this class is notkey value coding-compliant for the key %@.", NSStringFromClass([selfclass]), NSStringFromSelector(_cmd), key);
return nil;
}
@end
有問題+QQ648731281 ?歡迎騷擾 ? 相互交流學習