日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

iOS 如何让IOS应用从容地崩溃

發(fā)布時(shí)間:2025/7/25 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 iOS 如何让IOS应用从容地崩溃 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

雖然大家都不愿意看到程序崩潰,但可能崩潰是每個(gè)應(yīng)用必須面對的現(xiàn)實(shí),既然崩潰已經(jīng)發(fā)生,無法阻擋了,那我們就讓它崩也崩得淡定點(diǎn)吧。

閱讀器

經(jīng)驗(yàn)分享小技巧應(yīng)用崩潰

文/donglin

注:鑒于多名網(wǎng)友對文中代碼提出的質(zhì)疑,小編聯(lián)系了作者,迅速給予更正并更新。感謝大家的監(jiān)督與支持!

雖然大家都不愿意看到程序崩潰,但可能崩潰是每個(gè)應(yīng)用必須面對的現(xiàn)實(shí),既然崩潰已經(jīng)發(fā)生,無法阻擋了,那我們就讓它崩也崩得淡定點(diǎn)吧。

IOS SDK中提供了一個(gè)現(xiàn)成的函數(shù) NSSetUncaughtExceptionHandler 用來做異常處理,但功能非常有限,而引起崩潰的大多數(shù)原因如:內(nèi)存訪問錯(cuò)誤,重復(fù)釋放等錯(cuò)誤就無能為力了,因?yàn)檫@種錯(cuò)誤它拋出的是Signal,所以必須要專門做Signal處理。首先定義一個(gè)UncaughtExceptionHandler類,.h頭文件的代碼如下:

#import <UIKit/UIKit.h>

@interface UncaughtExceptionHandler : NSObject

{

BOOL dismissed;

}

@end

void InstallUncaughtExceptionHandler();

?

然后在.mm文件實(shí)現(xiàn)InstallUncaughtExceptionHandler(),如下:

void InstallUncaughtExceptionHandler()

{

signal(SIGABRT, MySignalHandler);

signal(SIGILL, MySignalHandler);

signal(SIGSEGV, MySignalHandler);

signal(SIGFPE, MySignalHandler);

signal(SIGBUS, MySignalHandler);

signal(SIGPIPE, MySignalHandler);

}

?

這樣,當(dāng)應(yīng)用發(fā)生錯(cuò)誤而產(chǎn)生上述Signal后,就將會(huì)進(jìn)入我們自定義的回調(diào)函數(shù)MySignalHandler。為了得到崩潰時(shí)的現(xiàn)場信息,還可以加入一些獲取CallTrace及設(shè)備信息的代碼,.mm文件的完整代碼如下:

#import "UncaughtExceptionHandler.h"

#include <libkern/OSAtomic.h>

#include <execinfo.h>

NSString * const UncaughtExceptionHandlerSignalExceptionName = @"UncaughtExceptionHandlerSignalExceptionName";

NSString * const UncaughtExceptionHandlerSignalKey = @"UncaughtExceptionHandlerSignalKey";

NSString * const UncaughtExceptionHandlerAddressesKey = @"UncaughtExceptionHandlerAddressesKey";

volatile int32_t UncaughtExceptionCount = 0;

const int32_t UncaughtExceptionMaximum = 10;

const NSInteger UncaughtExceptionHandlerSkipAddressCount = 4;

const NSInteger UncaughtExceptionHandlerReportAddressCount = 5;

@implementation UncaughtExceptionHandler

+ (NSArray *)backtrace

{

? ? ? ? void* callstack[128];

?int frames = backtrace(callstack, 128);

?char **strs = backtrace_symbols(callstack, frames);?

?int i;

?NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];

?for (

?i = UncaughtExceptionHandlerSkipAddressCount;

?i < UncaughtExceptionHandlerSkipAddressCount +

UncaughtExceptionHandlerReportAddressCount;

i++)

?{

?[backtrace addObject:[NSString stringWithUTF8String:strs[i]]];

?}

?free(strs);?

?return backtrace;

}

- (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex

{

if (anIndex == 0)

{

dismissed = YES;

}

}

- (void)handleException:(NSException *)exception

{

UIAlertView *alert =

[[[UIAlertView alloc]

initWithTitle:NSLocalizedString(@"Unhandled exception", nil)

message:[NSString stringWithFormat:NSLocalizedString(

@"You can try to continue but the application may be unstable.\n"

@"%@\n%@", nil),

[exception reason],

[[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]]

delegate:self

cancelButtonTitle:NSLocalizedString(@"Quit", nil)

otherButtonTitles:NSLocalizedString(@"Continue", nil), nil]

autorelease];

[alert show];

CFRunLoopRef runLoop = CFRunLoopGetCurrent();

CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);

while (!dismissed)

{

for (NSString *mode in (NSArray *)allModes)

{

CFRunLoopRunInMode((CFStringRef)mode, 0.001, false);

}

}

CFRelease(allModes);

NSSetUncaughtExceptionHandler(NULL);

signal(SIGABRT, SIG_DFL);

signal(SIGILL, SIG_DFL);

signal(SIGSEGV, SIG_DFL);

signal(SIGFPE, SIG_DFL);

signal(SIGBUS, SIG_DFL);

signal(SIGPIPE, SIG_DFL);

if ([[exception name] isEqual:UncaughtExceptionHandlerSignalExceptionName])

{

kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]);

}

else

{

[exception raise];

}

}

@end

NSString* getAppInfo()

{

? ? NSString *appInfo = [NSString stringWithFormat:@"App : %@ %@(%@)\nDevice : %@\nOS Version : %@ %@\nUDID : %@\n",

? ? ? ? ? ? ? ? ? ? ? ? ? [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"],

? ? ? ? ? ? ? ? ? ? ? ? ? [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"],

? ? ? ? ? ? ? ? ? ? ? ? ? [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"],

? ? ? ? ? ? ? ? ? ? ? ? ? [UIDevice currentDevice].model,

? ? ? ? ? ? ? ? ? ? ? ? ? [UIDevice currentDevice].systemName,

? ? ? ? ? ? ? ? ? ? ? ? ? [UIDevice currentDevice].systemVersion,

? ? ? ? ? ? ? ? ? ? ? ? ? [UIDevice currentDevice].uniqueIdentifier];

? ? NSLog(@"Crash!!!! %@", appInfo);

? ? return appInfo;

}

void MySignalHandler(int signal)

{

int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);

if (exceptionCount > UncaughtExceptionMaximum)

{

return;

}

?

NSMutableDictionary *userInfo =

[NSMutableDictionary

dictionaryWithObject:[NSNumber numberWithInt:signal]

forKey:UncaughtExceptionHandlerSignalKey];

NSArray *callStack = [UncaughtExceptionHandler backtrace];

[userInfo

setObject:callStack

forKey:UncaughtExceptionHandlerAddressesKey];

[[[[UncaughtExceptionHandler alloc] init] autorelease]

performSelectorOnMainThread:@selector(handleException:)

withObject:

[NSException

exceptionWithName:UncaughtExceptionHandlerSignalExceptionName

reason:

[NSString stringWithFormat:

NSLocalizedString(@"Signal %d was raised.\n"

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @"%@", nil),

signal, getAppInfo()]

userInfo:

[NSDictionary

dictionaryWithObject:[NSNumber numberWithInt:signal]

forKey:UncaughtExceptionHandlerSignalKey]]

waitUntilDone:YES];

}

void InstallUncaughtExceptionHandler()

{

signal(SIGABRT, MySignalHandler);

signal(SIGILL, MySignalHandler);

signal(SIGSEGV, MySignalHandler);

signal(SIGFPE, MySignalHandler);

signal(SIGBUS, MySignalHandler);

signal(SIGPIPE, MySignalHandler);

}

?

在應(yīng)用自身的 didFinishLaunchingWithOptions 前,加入一個(gè)函數(shù):

- (void)installUncaughtExceptionHandler

{

InstallUncaughtExceptionHandler();

}

?

最后,在 didFinishLaunchingWithOptions 中加入這一句代碼就行了:

[self InstallUncaughtExceptionHandler];

現(xiàn)在,基本上所有崩潰都能Hold住了。崩潰時(shí)將會(huì)顯示出如下的對話框:

?

這樣在崩潰時(shí)還能從容地彈出對話框,比起閃退來,用戶也不會(huì)覺得那么不爽。然后在下次啟動(dòng)時(shí)還可以通過郵件來發(fā)送Crash文件到郵箱,這就看各個(gè)應(yīng)用的需求了。

?

原文來自:觸控科技博客

轉(zhuǎn)載于:https://www.cnblogs.com/zsw-1993/archive/2013/06/07/4880035.html

總結(jié)

以上是生活随笔為你收集整理的iOS 如何让IOS应用从容地崩溃的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。