OC和Swift混编

作者: 大刘 | 来源:发表于2018-12-06 17:04 被阅读17次

    OC和Swift的混编,分为两种情况:

    • OC项目中嵌入Swift文件
    • Swift项目中嵌入OC文件

    先来看OC项目中嵌入Swift文件的情况

    新建一基于OC的项目,比如:OC_project

    接下来我们创建一个Swift类:BridgeTest.swift,并在里面新建一个类:Person

    -- Person.swift --
        
    import Foundation
    
    // public可以省略,外面同样可以调得到
    // 要OC调用到这个Swift类,则@objc不可省略,另外要直接或间接继承于NSObject
    @objc public class Person: NSObject { 
        // 为了让OC调用,方法同样需要@objc标示
        @objc
        func think() -> Void {
            print("person can think, it's important.")
        }
        
        @objc
        func eat() -> Void {
            print("person can eat, it's important.")
        }
        
        @objc
        func drink(_ water: String) -> Void {
            print("person can drink \(water), it's important")
        }
    }
    

    注:这里的Swift文件名叫BridgeTest.swift,而类名叫Person, 这并不是一个好的命名习惯,一般文件名和类名可以统一,在此写成不一样,是为了说明这和Java并不一样,在java中一个class被命名为public的,则此文件名必须和此public的类名相同,但swift中并没有这个限制。

    在新建这个Swift类时,Xcode会提示生成桥接文件:


    1.png

    这个桥接文件的作用主要是在Swift中调用OC的,我们暂且不理会,照提示确定即可。这会生成文件OC_project-Bridging-Header.h

    然后我们在OC的类里面调用这个Swift类:
    #import "ViewController.h"
    #import "OC_project-Swift.h" // 如果要使用Swift类,这个头文件需要添加,此文件是系统自动生成,不可见

    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        // 依赖于Apple自动生成的‘工程名-Swift.h’文件,本示例中是:OC_project-Swift.h
        // 其实在这个文件中声明了一些Swift到OC的转换后方法,因此我们可以以OC的调用方式调用Swift方法
        Person *p = [[Person alloc] init];
        NSLog(@"%@", p);
        [p think];
        [p eat];
        [p drink:@"咖啡"];
    }
    

    注意,一般这样做就可以了,但Xcode有时候会抽疯的,因此如果有问题我们需要检查Xcode的设置:

    • Defines Module : YES

      2.png
    • Product Module Name : yourProjectName

      3.png
      Make sure that your Product Module Name doesn't contain any special characters.
    • Install Objective-C Compatibility Header : YES

      4.png
      Once you've added *.swift file to the project this property will appear in Build Settings。
    • Objective-C Generated Interface Header : yourProject-Swift.h

      5.png
      This header is auto generated by Xcode
    • Objective-C Bridging Header : $(SRCROOT)/yourProject-Bridging-Header.h

      6.png

    上面是让OC调用Swift方法,下面我们依然基于这个OC项目,让Swift调用OC,在做这个之前我们需要知道一个概念:

    Objective-C调用Swift: 需要在暴露出来的Swift方法和属性上加@objc标识,否则不可用;且文件的类需要继承自NSObject或NSObject的子类。另外如果仍有问题,需要在工程配置里面做一些小改动。
    Swift调用Objective-C: 需要在统一的bridge头文件(YourProjectName-Bridging-Header.h)里面import,然后即可使用。

    在上面的示例中, 使用OC调Swift并不需要使用桥接文件, 但如果要让Swift调OC,则需要在这个文件中import要在Swift中使用的OC类的头文件。
    接下来我们新建一个OC的Dog类,让Swift方法调用这个Dog类的方法。

    -- Dog.h --
    @interface Dog : NSObject
    
    - (void)think;
    - (void)eat:(NSString *)food;
    @end
    
    -- Dog.m --
    @implementation Dog
    
    - (void)think {
        NSLog(@"Dog can think, but it's different with person's think");
    }
    
    - (void)eat:(NSString *)food {
        NSLog(@"%@", [NSString stringWithFormat:@"dog can eat: %@, it's important", food]);
    }
    
    @end
    

    然后在BridgeTest.swift中的Person类中添加两个方法:

    @objc
    func dogThink() -> Void {
        let dog: Dog = Dog()
        dog.think()
    }
    
    @objc
    func dogEat(_ food: String) -> Void {
        let dog: Dog = Dog()
        dog.eat(food)
    }
    
    -- OC_project-Bridging-Header.h --
    #import "Dog.h"
    
    -- ViewController.m --
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        // 依赖于Apple自动生成的‘工程名-Swift.h’文件
        Person *p = [[Person alloc] init];
        NSLog(@"%@", p);
        [p think];
        [p eat];
        [p drink:@"咖啡"];
        [p dogThink]; // 添加
        [p dogEat:@"狗粮"]; // 添加
    }
    
    @end
    

    以上是基于OC项目嵌入Swift文件,接下来我们在Swift项目中嵌入OC文件

    Swift项目中嵌入OC文件相对比较简单,新建一基于Swfift的项目,比如:Swift_project, 然后新建OC类,在新建的时候同样按照系统提示生成bridge文件。

    如果Swift类要调用OC,只须在Swift_project-Bridging-Header.h中#import相对应的OC类即可。如果OC类要调用Swift, 只需#import "Swift_project-Swift.h"即可。

    示例:

    -- Person.h --
    @interface Person : NSObject
    
    - (void)think;
    - (void)dogThink;
    
    @end
    
    -- Person.m --
    #import "Person.h"
    #import "Swift_project-Swift.h"
    
    @implementation Person
    
    - (void)think {
        NSLog(@"think");
    }
    
    - (void)dogThink {
        Dog *d = [[Dog alloc] init];
        [d think];
    }
    
    @end
    
    
    -- Dog.swift --
    import UIKit
    
    @objc
    class Dog: NSObject {
        @objc
        public func think() -> Void {
            print("dong think, but different with person")
        }
    }
    
    -- Swift_project-Bridging-Header.h --
    #import "Person.h"
    
    -- ViewController.swift --
    class ViewController: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
         
            let p: Person = Person()
            p.think()
            p.dogThink()
        }
    }
    

    相关文章

      网友评论

        本文标题:OC和Swift混编

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