优雅的开发Swift和Objective C混编的Framework

转载自http://blog.csdn.net/hello_hwc/article/details/58320433

前言

为什么要写这样一篇文章,因为昨天和一个朋友讨论到Swift和Objective C如何混合开发Framework,中途发现了很多有意思的坑。

用Swift封装OC的库是一件比较常见的事情,毕竟对于大多数公司来说,老的代码都是用OC写的,而且经过多次迭代,这些OC的代码已经被验证了是稳定的,用Swift重写代价太大。这就引入了一个需求:

  • 用Swift和OC来混编一个Framework。

如果你之前没有用Swift和Objective C混合开发,建议看看这篇文档:

这篇文档很详细的讲解了如何运用Objective C和Swift进行混合开发App和Framework。于是,我们先按照文档来写一个混编的Framework


按照文档一步一步来

新建一个基于单页面工程,然后新建一个一个Target,选中Cocoa Touch Framework。然后,分别新建一个Swift文件和Objective C类,注意Target Member Ship选中Framework。类的内容如下:

OCSource.h

#import <Foundation/Foundation.h>

@interface OCSource : NSObject
- (void)functionFromOC;
@end

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

OCSource.m

#import "OCSource.h"

@implementation OCSource

- (void)functionFromOC{
    NSLog(@"%@",@"Log from objective c in framework");
}
@end


 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Swift调用OC

新建SwiftSource.swift

open class SwiftIt{
    public init(){}
    let ocObject = OCSource()
    public func encapsulate(){
        ocObject.functionFromOC()
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

然后,按照文档中,为了让Swift文件访问Objective C文件,我们应该在umbrella header,也就是MixFramework.h中,暴露所需要的header。

也就是,MixFramework.h,

#import <MixFramework/OCSource.h>
 
 
  • 1
  • 1

然后,自信满满的点击build。

Boom~~~,编译不通过。

原因:OCSource.h默认编译的时候是Project权限. 为了在umbrella header中使用,要把这个文件的权限改成Public

按照图中的方式拖过去即可。

嗯,现在build,可以看到build成功了。

OC调用Swift

在SwiftSource.swift中,增加一个类,

open class ClassForOC:NSObject{
    public static let textForOC = "textForOC"
}
 
 
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

然后,为了在OC中调用Swift的方法,我们需要导入头文件,这时候,OCSource.m文件内容如下

#import "OCSource.h"
#import <MixFramework/MixFramework-Swift.h>

@implementation OCSource

- (void)functionFromOC{
    NSLog(@"%@",[ClassForOC textForOC]);
}
@end
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

然后,build,发现成功了,很开心。


外部调用

在ViewController.swift中,我们调用Framework中的内容。

import MixFramework
class ViewController: UIViewController {
    var t = SwiftIt()
    override func viewDidLoad() {
        super.viewDidLoad()
        t.encapsulate()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

然后运行,发现控制台打印出

2017-03-02 16:08:24.000 HostApplication[19524:167669] textForOC
 
 
  • 1
  • 1

嗯,framework打包成功了。


问题

通常,我们希望暴露给外部的接口是纯Swift,而OC文件的具体接口应该隐藏,这就是我标题中的优雅两个字的含义。

如果你好奇,你会发现,在ViewController.swift中你可以这么调用

    var s = OCSource()
 
 
  • 1
  • 1

也就是说,OC的内容也暴露出来了,这破坏了Framework的封装特性

通过查看MixFramework的编译结果,发现最后暴露出的接口是这样子的

import Foundation
import MixFramework.OCSource
import MixFramework
import MixFramework.Swift
import SwiftOnoneSupport
import UIKit

//
//  MixFramework.h
//  MixFramework
//
//  Created by Leo on 2017/3/2.
//  Copyright © 2017年 Leo Huang. All rights reserved.
//

//! Project version number for MixFramework.
public var MixFrameworkVersionNumber: Double
open class ClassForOC : NSObject {

    public static let textForOC: String
}

open class SwiftIt {

    public init()

    public func encapsulate()
}


 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

这一行,把OC对应的实现暴露出来了

import MixFramework.OCSource
 
 
  • 1
  • 1

优雅的解决方案

不再通过umbrella header的方式让framework中的Swift调用OC方法。而是通过modulemap

新建一个module.modulemap文件,内容如下


module OCSource [system] {
    //由于module.modulemap和OCSource.h是在同一个文件夹的,如果不是同一个,路径要写全
    header "OCSource.h"
    export *
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这里的#(SRCROOT)是XCode的宏,会自动替换成项目所在的根目录,这里输入的路径是module.modulemap文件所在的路径。

然后,删除MixFramework.h(umbrella header)中#import 的OC header。

把OCSource.h的权限改回默认的project。

再编译,发现OC的类被隐藏了。


总结

如果你要开发一个framework,一定要想清楚哪些接口暴露出去,哪些封装起来,framework不是简单把一包文件加个壳子。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值