版本兼容性检查
检查某个系统常量是否存在
- 比如UIKeyboardFrameEndUserInfoKey是从iOS 3.2开始支持的, 要在之前的系统版本中使用该值, 需使用UIKeyboardBoundsUserInfoKey.
if (&UIKeyboardFrameEndUserInfoKey != nil) - {
- // Available.
- }
- else
- {
- // Do something else.
- }
检查某个系统类库是否存在
- 比如在iOS 4.0之后加入了ALAssetsLibrary.
Class ALAssetsLibraryClass = NSClassFromString(@"ALAssetsLibrary"); - if (ALAssetsLibraryClass)
- {
- // Do something related to the library.
- }
检查某个函数是否存在
- ImageIO是iOS 4.0之后才有的类库, 但它是一套C的类库, 要检查其是否存在, 就要检查某个函数是否存在.
系统声明如下:
IMAGEIO_EXTERN CGImageSourceRef CGImageSourceCreateWithData(CFDataRef data, CFDictionaryRef options) IMAGEIO_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_4_0);
检查方法:
if (CGImageSourceCreateWithData != NULL)- {
- // ImageIO exists.
- }
检查某个类是否实现指定方法
- iOS 4.0中的ALAssetsLibrary, 可以将照片存入系统相册, 但是iOS 4.0和iOS 4.1有不同的方式调用存入相册的方法. 以下存入相册的方法分为三种:
- 系统支持带入元数据存入相册 (iOS 4.1及以上)
- 系统支持带入相片方向存入相册 (iOS 4.0及以上)
- 原始存入相册方式 (iOS 2.0及以上)
// 如果支持Assets, 则使用Assets. - Class ALAssetsLibraryClass = NSClassFromString(@"ALAssetsLibrary");
- if (ALAssetsLibraryClass)
- {
- ALAssetsLibrary *assetsLibrary = [[[ALAssetsLibrary alloc] init] autorelease];
- if (&UIImagePickerControllerMediaMetadata != nil && [assetsLibrary respondsToSelector:@selector(writeImageToSavedPhotosAlbum:metadata:completionBlock:)])
- {
- // 如果支持存储metadata, 则存储. 4.1及以上支持.
- [assetsLibrary writeImageToSavedPhotosAlbum:[originalImage CGImage]
- metadata:[info objectForKey:UIImagePickerControllerMediaMetadata]
- completionBlock:^(NSURL *assetURL, NSError *error) {
- }];
- }
- else if ([assetsLibrary respondsToSelector:@selector(writeImageToSavedPhotosAlbum:orientation:completionBlock:)])
- {
- // 如果不支持存储metadata, 则只存储图片和方向. 4.0及以上支持.
- [assetsLibrary writeImageToSavedPhotosAlbum:[originalImage CGImage]
- orientation:(ALAssetOrientation)[originalImage imageOrientation]
- completionBlock:^(NSURL *assetURL, NSError *error) {
- }];
- }
- }
- else
- {
- UIImageWriteToSavedPhotosAlbum(originalImage, NULL, NULL, NULL);
- }
- 检测系统是否支持多任务
- (BOOL)isMultitaskingCapable - {
- UIDevice *device = [UIDevice currentDevice];
- BOOL backgroundSupported = NO;
- if ([device respondsToSelector:@selector(isMultitaskingSupported)])
- {
- backgroundSupported = device.multitaskingSupported;
- }
- return backgroundSupported;
- }
具体案例
设置UIWindow的rootViewController
iOS 3.x中UIWindow采用加入view的方式, iOS 4.0及以上系统采用了直接设置rootViewController的方式. 推荐使用最新的API, 而兼容iOS 3.x的API.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
if ([UIWindow instancesRespondToSelector:@selector(rootViewController)])
{
self.window.rootViewController = self.viewController;
}
else
{
[self.window addSubview:self.viewController.view];
}
[self.window makeKeyAndVisible];
return YES;
}
调试
日志开关
- 一般来讲在应用提交App Store时需要关闭NSLog打印出来的日志信息. 如果时临时注释代码的方式, 会比较繁琐, 也容易出错. 可以采用声明一个宏的方式, 只有在调试模式才开启NSLog输出的日志.
#ifdef DEBUG - # define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
- #else
- # define DLog(...)
- #endif
- // ALog always displays output regardless of the DEBUG setting.
- #define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
甚至可以加入UIAlertView的提醒.
#ifdef DEBUG- # define ULog(fmt, ...) { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:@"%s\n [Line %d] ", __PRETTY_FUNCTION__, __LINE__] message:[NSString stringWithFormat:fmt, ##__VA_ARGS__] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertView show]; [alertView release]; }
- #else
- # define ULog(...)
- #endif
NSZombieEnabled
- 当程序是因为EXC_BAD_ACCESS而崩溃的情况时, 可以考虑在环境变量中开启NSZombieEnabled. 开启后会把object错误释放的消息打印在控制台上.
NSAssert
- 使用NSAssert可以在开发过程中非常方便的确定问题所在,但是在发布程序时需要手动隐藏掉这些用于调试的assert。方法:设置编译属性,在Build Settings页面中修改 Preprocessing Macros的值,对 release 和 distribution 增加 NS_BLOCK_ASSERTIONS