上次说到了iphone5的一些兼容性解决的东西,这次谈一下平时开发时遇到的一些iOS6的兼容性问题。
1、首先是Oritentation问题:
这里可以看这篇翻译:http://blog.csdn.net/sandy_kisa/article/details/8037699
但事实上iOS6对于plist非常敏感,如果仅仅按照上面改可能还是会出现问题,我就碰到了,如果plist中UISupportedInterfaceOrientations项目的原有支持三个方向改为只有一个:Portrait (bottom home button),这样就没啥问题了
2、UIImageView上的UIButton点击触发问题:
在iOS6一下的版本我们如果在UIImageView addSubview一个UIButton,则对该button进行事件触发绑定是办不到的,而在iOS6中又是可以的,可能是apple发现了这个存在的bug。(有人会问干嘛要直接在image上add一个button啊,在view上直接叠加不就行了,但是如果要做图片的选择等操作,add在image上的复杂度会比直接再view上add要低很多)
我们做兼容可以这样:
-(void)viewDidLoad { singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)]; [self.view addGestureRecognizer:singleTap]; } -(void)handleSingleTap:(UITapGestureRecognizer*)gesture { if (gesture.state == UIGestureRecognizerStateEnded) { CGPoint tapPoint = [gesture locationInView:blackBackgroundView]; if ((tapPoint.x > (ScreenWidth - 75) && tapPoint.y > (ScreenHeight - 75) && !isPhotoGif) || (tapPoint.x > (ScreenHeight - 75) && tapPoint.y > (ScreenWidth - 75) && !isPhotoGif)) { [self saveButtonPressed:nil]; return; } }
上面对于tap手势的point进行判断再触发,而在ios6中则是直接绑定事件触发器
【2013.5.14补充】后来发现其实原因是iOS6中直接给UIImageView的userInteractionEnabled开启为YES的缘故,事实上本来就能够通过userInteractionEnabled改为YES解决上述UIButton在UIImageView中无法响应的问题。
3、通讯录的隐私问题
iOS6中新增加了用户的隐私设置,所以在app需要访问用户的通讯录的时候需要用户允许。而以前广泛用的ABContact类库不包含这些东西。我们现在要对ABContact进行更改:
iOS中新增ABAddressBookCreateWithOptions方法我们要加入ABContact中,尼玛ABContact这货三年没更新了。。。
将原来getter方法:
+ (ABAddressBookRef) addressBook { return CFAutorelease(ABAddressBookCreate()); }
改为:
+ (ABAddressBookRef) addressBook { ABAddressBookRef addressBook = nil; if ([[UIDevice currentDevice].systemVersion floatValue] >= 6.0) { addressBook = ABAddressBookCreateWithOptions(NULL, NULL); //等待同意后向下执行 dispatch_semaphore_t sema = dispatch_semaphore_create(0); ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { dispatch_semaphore_signal(sema); }); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); dispatch_release(sema); } else { addressBook = ABAddressBookCreate(); } return CFAutorelease(addressBook); }
上面的代码是一个需要用户同意的代码片段。
接着要对其余的CFAutorelease(ABAddressBookCreate())语句改为[selfaddressBook],尼玛重复代码不带这么玩的。。。
+ (NSArray *) contacts { ABAddressBookRef addressBook = CFAutorelease(ABAddressBookCreate()); NSArray *thePeople = (NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook); NSMutableArray *array = [NSMutableArray arrayWithCapacity:thePeople.count]; for (id person in thePeople) [array addObject:[ABContact contactWithRecord:(ABRecordRef)person]]; [thePeople release]; return array; }
改为:
+ (NSArray *) contacts { ABAddressBookRef addressBook = [self addressBook]; NSArray *thePeople = (NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook); NSMutableArray *array = [NSMutableArray arrayWithCapacity:thePeople.count]; for (id person in thePeople) [array addObject:[ABContact contactWithRecord:(ABRecordRef)person]]; [thePeople release]; return array; }
好,这丫的通讯录问题就解决了。
4、键盘中文输入后未关锁屏之后直接crash
这是个棘手的问题,因为我们根本不知道它到底哪儿出了问题,而且这个问题在以前iOS5等版本中都是好的。
这个问题的描述可以参看这个问题帖子:http://www.cocoachina.com/ask/questions/show/57585
在uitextview 或者 uitextfield里输入中文,键盘开着的状态下直接锁屏再开就会crash,里面也说道再系统设置、通用、还原、还原键盘字典就能解决问题,但能否从代码层面阻止这种crash
事实上中文输入在锁屏时会对用户输入的pinyin进行重置,而这部分在iOS6下会直接终止,导致crash,我们可以把它的运行放到后台的短进程里。可以这样做:
- (void)applicationDidEnterBackground:(UIApplication *)application { // ios6中文输入后锁屏之后就会crash,加上之后不会 if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0)) { if (!backgroundTask || backgroundTask == UIBackgroundTaskInvalid) { backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{ dispatch_async(dispatch_get_main_queue(), ^{ if (backgroundTask != UIBackgroundTaskInvalid) { [application endBackgroundTask:backgroundTask]; backgroundTask = UIBackgroundTaskInvalid; } }); }]; } } }
上述代码是开一个后台task再在主线程里对它进行安全的endtask,这样就不会导致crash的问题了。
【2013.5.14更新】
5、关于sizeof线程安全的规避
在iOS6中对于NSString size计算会出现线程问题,例如下面代码如果dispatch到一个非主线程队列里,就很可能导致Crash
letterSize = [c sizeWithFont:_contentFont];
我们需要采用下面的做法:
NSAttributedString *attribStr = [[[NSAttributedString alloc] initWithString:c attributes:[NSDictionary dictionaryWithObject:_contentFont forKey:NSFontAttributeName]] autorelease]; letterSize = [attribStr size];
但是上述方法只适用于iOS6,so
CGSize letterSize; if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0)) { NSAttributedString *attribStr = [[[NSAttributedString alloc] initWithString:c attributes:[NSDictionary dictionaryWithObject:_contentFont forKey:NSFontAttributeName]] autorelease]; letterSize = [attribStr size]; } else { letterSize = [c sizeWithFont:_contentFont]; // 字符尺寸 }
具体参照 http://stackoverflow.com/questions/12744558/uistringdrawing-methods-dont-seem-to-be-thread-safe-in-ios-6