美文网首页
iOS 13适配填坑总结

iOS 13适配填坑总结

作者: Hedgehog___ | 来源:发表于2019-10-30 11:58 被阅读0次

    前言

      前段时间苹果发布了最新系统iOS 13,开发者当然避免不了去适配最新的系统版本,以下我总结了在适配过程中遇到的问题以及坑。

    1、获取当前控制器

      我在适配iOS 13之前获取当前控制器的方法是这样的

    - (UIViewController *)currentViewController {
       UIViewController *result = nil;
        UIWindow *keyWindow = [UIApplication sharedApplication].delegate.window;
        if (keyWindow.windowLevel != UIWindowLevelNormal) {
            NSArray *windows = [UIApplication sharedApplication].windows;
            for (UIWindow *tempWindow in windows) {
                if (tempWindow.windowLevel == UIWindowLevelNormal) {
                   keyWindow = tempWindow;
                     break;
                 }
             }
         }
       id nextResponder = [[keyWindow.subviews firstObject] nextResponder];
        if ([nextResponder isKindOfClass:[UITabBarController class]]) {
            UITabBarController *tabBarController = (UITabBarController*)nextResponder;
            result = tabBarController.selectedViewController;
           if ([result isKindOfClass:[UINavigationController class]]) {
                UINavigationController *naviC = (UINavigationController*)result;
                result = naviC.visibleViewController;
             }
        } else if ([nextResponder isKindOfClass:[UINavigationController class]]) {
            UINavigationController *naviC = (UINavigationController*)nextResponder;
            result = naviC.visibleViewController;
        } else if ([nextResponder isKindOfClass:[UIViewController class]]) {
            result = (UIViewController*)nextResponder;
       } else {
            result = keyWindow.rootViewController;
         }
         
        return result;
     }
    

    打断点发现:

    image.png
    keywindownextResponder居然在iOS 13 中居然也变成了UIWindow
    所以我们可以通过绕过nextResponder来获取当前控制器:
    -(UIViewController *)currentViewController{
        UIWindow *window = [UIApplication sharedApplication].delegate.window;
        NSLog(@"window level: %.0f", window.windowLevel);
        if (window.windowLevel != UIWindowLevelNormal) {
            NSArray *windows = [[UIApplication sharedApplication] windows];
            for (UIWindow * tmpWin in windows) {
                if (tmpWin.windowLevel == UIWindowLevelNormal) {
                    window = tmpWin;
                    break;
                }
            }
        }
        
        //从根控制器开始查找
        UIViewController *rootVC = window.rootViewController;
        UIViewController *activityVC = nil;
        
        while (true) {
            if ([rootVC isKindOfClass:[UINavigationController class]]) {
                activityVC = [(UINavigationController *)rootVC visibleViewController];
            } else if ([rootVC isKindOfClass:[UITabBarController class]]) {
                activityVC = [(UITabBarController *)rootVC selectedViewController];
            } else if (rootVC.presentedViewController) {
                activityVC = rootVC.presentedViewController;
            }else {
                break;
            }
            
            rootVC = activityVC;
        }
        
        return activityVC;
    }
    

    解决。

    2、UIWebView的执行JS脚本方法回调线程问题

      在iOS 13之前中用JSContext执行脚本方法回调的block是在主线程的,可以之间在里面修改UI布局,但是在iOS 13中突然就崩溃了,我在调试中发现了这个回调block居然不在主线程了,崩溃的原因也是因此。

    image.png
    image.png

    临时解决方法是加一个安全线程的调用:

    #define dispatch_main_async_safe(block)\
        if ([NSThread isMainThread]) {\
            block();\
        } else {\
            dispatch_async(dispatch_get_main_queue(), block);\
        }
    

    首先声明这个方法只是临时阻止UIWebViewcrash的一种临时方法,本人并不建议这么做,更好的的方法是更换WKWebView,因为UIWebView在iOS 12就已经被废弃。

    image.png
    3、暗黑模式(Dark Model)

    两种方法:
    1)直接全局关闭暗黑模式(不建议)
    info.plist中加入:key 为User Interface Style value类型为String值为Light可直接全局禁用暗黑模式
    2)根据风格适配
    我借鉴了这篇文章

    4、UIViewController的UIModalPresentationStyle属性

    在iOS 13未适配的时候突然发现present出来的控制器样式变了,在查看了相关属性的情况之后发现了UIModalPresentationStyle新增了一个枚举值UIModalPresentationAutomatic在iOS 13之后控制的默认值就是这个,要想恢复之前的模态跳转样式需要设置控制器UIModalPresentationStyleUIModalPresentationFullScreen就好:

    if (@available(iOS 13.0, *)) {//iOS 13 默认不使用 UIModalPresentationFullScreen 模式
                self.modalPresentationStyle =  UIModalPresentationFullScreen; 
    }
    
    5、UITextField的leftview

    在iOS 13中突然发现我的UITextfield leftview显示有点怪,然后发现如果直接给 textfield.leftView 赋值一个 UILabel 对象,他的宽高会被 sizeToFit。解决方法:给label套一层UIView的父视图在设置leftview。解决

    6、Push推送获取的token的变化

    在iOS 13的系统版本中,token的格式发生了变得,导致不能按照iOS13之前的处理方法去处理然后再上传服务器。

    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
        DBLOG_FUN;
       NSString *_deviceToken = @"";
       if (@available(iOS 13.0, *)) {
          if (![deviceToken isKindOfClass:[NSData class]]) return;
          const unsigned *tokenBytes = [deviceToken bytes];
          _deviceToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                                ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
                                ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
                                ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
          [[DataStore sharedStore] setDeviceToken:_deviceToken];
          DBLOG(@"_deviceToken:%@", _deviceToken);
       }else if([deviceToken.description length] > 0) {
            NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@"<>"];
            _deviceToken = [deviceToken.description stringByTrimmingCharactersInSet:set];
            _deviceToken = [_deviceToken stringByReplacingOccurrencesOfString:@" " withString:@""];
            [[DataStore sharedStore] setDeviceToken:_deviceToken];
            DBLOG(@"_deviceToken:%@", _deviceToken);
        }
    }
    
    7、UITextfield通过KVC修改placeholderlabel方法

    在iOS 13中通过以下方法修改UITextfield的placeholder会发生crash:

    // 使用的私有方法
    [_textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
    

    解决方法有两种:
    1)把前面的下划线去掉(不建议)

    [_textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
    

    2)通过attributedPlaceholder设置(建议)

    _textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"输入"attributes:@{NSForegroundColorAttributeName: [UIColor redColor]}];
    
    待续。。。

    相关文章

      网友评论

          本文标题:iOS 13适配填坑总结

          本文链接:https://www.haomeiwen.com/subject/mcnfvctx.html