iOS版本兼容

编译时判断:检查SDK版本(app编写时xcode版本对应的iOS版本);运行时判断:检查当前系统版本

//
//  ViewController.m
//  test
//
//  Created by yy on 2017/11/20.
//  Copyright © 2017年 zg. All rights reserved.
//
// 参考:http://www.360doc.com/content/16/0118/09/30240408_528773083.shtml

#import "ViewController.h"

@interface ViewController ()

@end


@implementation ViewController



- (void)viewDidLoad {
    [super viewDidLoad];
   /*
    一:Deployment Target(APP能支持的最低系统版本,如要支持iOS8及以上)
    二:Base SDK:编译APP的SDK的版本,一般保持当前XCode支持的最新,所以Base SDK肯定是大于等于Deployment Target的版本。
    三:既然Base SDK的版本大于等于Deployment Target的版本,那么就要小心了,只要用到的类、方法,在当前的Base SDK版本里面存在,就可以编译通过!但是一旦运行APP的手机的系统版本低于这些类、方法的最低版本要求,APP就会Crash!
    五:
    __IPHONE_OS_VERSION_MAX_ALLOWED: 值等于Base SDK,即用于检查SDK版本的。
    __IPHONE_OS_VERSION_MIN_REQUIRED:值等于Deployment Target,检查支持的最小系统版本。
    */
    [self test];
}

// 宏只在编译时生效!
// 编译时判断:检查SDK版本;运行时判断:检查当前系统版本
- (void)test{
#if __IPHONE_OS_VERSION_MAX_ALLOWED > 80000
    if([[[UIDevice currentDevice] systemVersion] floatValue] > 8 ){
        NSLog(@"大于8");
    }else{
        NSLog(@"小于8");
    }
#else
#endif
}

运行时检查类、方法是否可用

//运行时检查类、方法是否可用
- (void)test2 {
    // 1.
    if ([UIAlertController class]) {
        NSLog(@"yes");
    }
    
    // 2.
    Class class = NSClassFromString(@"UIAlertController");
    if (class) {
        NSLog(@"yes");
    }
    
    // 3.方法
    if ([self.view respondsToSelector:@selector(safeAreaInsetsDidChange)]) {
        NSLog(@"可以执行safeAreaInsetsDidChange");
    }
    
}

Method Swizzling做兼容

//
//  UILabel+LabelBackGroundColor.h
//  test
//
//  Created by yy on 2017/11/20.
//  Copyright © 2017年 zg. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface UILabel (LabelBackGroundColor)

@end





//
//  UILabel+LabelBackGroundColor.m
//  test
//
//  Created by yy on 2017/11/20.
//  Copyright © 2017年 zg. All rights reserved.
//

#import "UILabel+LabelBackGroundColor.h"
#import <objc/runtime.h>

@implementation UILabel (LabelBackGroundColor)

//Method Swizzling的影响是全局的,多次调用的话,会出错,这个时候可以用dispatch_once
//如UILabel的背景色在iOS6上,默认是白色,而iOS6以后是透明的!如果在每个用到UILabel的地方,都手动设置一次背景色,代价太大。这个时候就需要Runtime的“黑魔法”上场。
+(void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if ([[UIDevice currentDevice] systemVersion].floatValue >= 7.0f) {
            // Method Swizzling --> initWithFrame
            Method oldMethod = class_getInstanceMethod(self, @selector(initWithFrame:));
            Method newMethod = class_getInstanceMethod(self, @selector(newInitWithFrame:));
            method_exchangeImplementations(oldMethod, newMethod);
        }
    });
}

// 新的方法
- (id)newInitWithFrame:(CGRect)frmae{
    
//  直觉会告诉你在一个方法的实现中通过self调用当前方法自身会产生错误,
//  如果我们在这个方法中调用initwithframe:才会真的导致死循环,因为这个方法的实现会在运行时被swizzle到newInitWithFrame:的选择器
    id newSelf = [self newInitWithFrame:frmae];
    ((UILabel*)newSelf).backgroundColor = [UIColor redColor];
    return newSelf;
}


@end

// Method Swizzling做兼容
/*在Objective-C中,运行时会自动调用每个类的两个方法。+ (void)load会在类、Category初始加载时调用,+ (void)initialize会在第一次调用类的类方法或实例方法之前被调用。
 但是,+ (void)initialize是可以被Category覆盖重写的,并且有多个Category都重写了 + (void)initialize方法时,只会运行其中一个,所以在 + (void)initialize里面做Method Swizzling显然是不行的, + (void)load方法只要实现了,就一定会调用。*/

- (void)methodSwizzle {
    UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(50, 50, 100, 30)];
    label.text = @"test";
    [self.view addSubview:label];
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值