【iOS】iOS6兼容性问题小结

  上次说到了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

猜你喜欢

转载自leyteris.iteye.com/blog/1735564