2018-01-29 17:29:59 qq_30670353 阅读数 2023
关于object-cswift混编问题,无论是在oc基础上添加swift还是在swift上添加oc最后打出来的ipa的包都会大一到两倍。因为这个原因可能有很多人会放弃混编,但是不用害怕,上传iTunes之后,ipa会压缩回正常大小
2017-05-06 18:47:20 wangdong_333 阅读数 2972

最近由于项目需求需要使用Swift做开发,但之前的好多有用的东西都是使用OC写的,鉴于这种情况最好的方式当然是使用swift重写,但这样的工作量太大,而且不能保证功能的稳定性,所以自己就尝试的使用Framework来嵌入Swift项目中去。

至于涉及到OC和Swift汇编的过程可以看我上一篇文章

首先我们需要了解framework是什么:

  • Framework 就是一个Bundle,将所有的资源(nib, Images, Fonts…)和代码都打包在一起,方便发布。理论上动态库可以单独更新,只是在iOS 上Apple未开放这样的权限。
  • 首先我们创建一个Cocoa Touch Framework工程命名为SwiftOCFramework,默认会生成这么几个文件:
  •  
  • 然后把自己需要打包成framework的文件拖入该工程中,这个时候就不需要使用xxx-swift.h文件了,不要把这个文件加入进来:
  • 编译一下发现会报错,这就正常了:

  • 这是因为我们没有使用桥接文件来引入OC的头文件导致的,接下来默认生成的SwiftOCFramework.h就有作用了,因为我们这个是Framework所以在SwiftOCFramework.h中引入头文件时要这样写:#import <SwiftOCFramework/TestOCFile.h>,同时既然TestOCFile.h是给Swift文件用的那么我们就需要在Build Phases-Headers中把它指定为public,直接从Project中拖上去即可:

  • SwiftOCFramework.h文件现在是这样的:

  • 这样我们就引入了OC文件,再次编译运行发现还是有错,奔溃了,仔细看一下,不难发现是在OC调用Swift时出错,引入的桥接头文件出错:

  • 仔细观察大家应该能看出问题来,我们在创建OC和Swift汇编工程时名字为SwiftOCCallBack,那么对应生成的桥接文件就是#import "SwiftOCCallBack-Swift.h",但是现在我们打包的工程名字已经更改了,这就是导致找不到文件的原因。
  • 在创建Swift工程时,系统会自动根据工程名称生成对应的桥接文件,这时我们是不是可以改一下这个桥接文件试一下,发现还是一样的错误,什么原因:

  • 什么鬼,长长的舒了一口气,仔细认真一想,现在我们是在创建Framework,一般我们引用Framework中的文件是怎么使用的framework/xxx.h是吧,这样修改一下:

  • 终于出现BUlid Succeeded了,感谢国家,感谢党啊,接着就是我们需要合并Framework了
  • 修改BUlid Configuration:

  • 这个时候我们在Run一下真机以及模拟器,这两个文件就是我们想要的:

  • 合并一下,打开终端执行下面命令,一般我是使用Release-iphoneos复制一份,然后在把Release-iphoneos和Release-iphonesimulator中的SwiftOCFramework文件合并,一般是直接找到文件拖入终端就可;
  • lipo -create /Users/FLY/Desktop/PROJECT/untitledfolder/SwiftOCFramework/Release-iphoneos/SwiftOCFramework.framework/SwiftOCFramework /Users/FLY/Desktop/PROJECT/untitledfolder/SwiftOCFramework/Release-iphonesimulator/SwiftOCFramework.framework/SwiftOCFramework -output /Users/FLY/Desktop/PROJECT/untitledfolder/SwiftOCFramework/SDK/Release-iphoneos/SwiftOCFramework.framework/SwiftOCFramework 


    点击回车搞定,但这时由于我们没有合并SwiftOCFramework.swiftmodule文件,所以还是智能在真机上运行,OK我们直接把elease-iphonesimulator中的SwiftOCFramework.swiftmodule文件文件复制到Release-iphoneos中,然后倒入工程运行,OK。
  • 刚开始我们会遇到一下错误:

  • 这是因为我们没有告诉工程我们新嵌入了Framework,工程运行时找不到,我们需要手动嵌入二进制framework:

  • 再次运行,OK了:

2016-06-14 16:42:28 ismilesky 阅读数 2932

概述

Swift的设计的初衷就是摆脱ObjC沉重的历史包袱,毕竟ObjC的历史太过悠久,相比于很多现代化语言它缺少一些很酷的语法特性,而且ObjC的语法和其他语言相比差别很大。随着Swift的改进及Swift开源项目剧增,越来越多的Objective-C工程开始使用Swift混编,不管是在基于Swift工程中或者Objective-C工程中,Swift和Objective-C文件都可以无缝结合。本文首先介绍下Swift与Objective-C混编的基本使用。

Objc与Swift的渊源

通过对swift的了解,大家不难发现Swift和ObjC必然存在着一定的映射关系,例如对于文件的操作使用了字符串的writeToFile方法,在网络请求时使用的NSURLSession,虽然调用方式不同但是其参数完全和做ObjC开发时调用方式一致。原因就是Swift编译器自动做了映射,如下图:(PS:借来的图)

这里写图片描述

Objc和Swift的相互调用

切入正题,当我们使用OC和Swift在工程中进行混编的时候,通俗来说其实Objc文件和swift文件之间的相互调用。不管你的项目是基于Swift还是基于Objc的,无论是Swift中调用ObjC,还是ObjC中调用Swift都是通过头文件暴漏对应接口的,下图说明了这种交互方式:

这里写图片描述


  • Swift调用Objc

下面我们先建个Objc的工程,在Objc工程中新建Swift文件时,(或者在Swift工程新建Objc文件),Xcode会自动提示你是否创建bridging header桥接头文件,点击创建后Xcode会自动为你创建一个桥接头文件。Xcode会自动创建一个名为OC_Swift-Bridging-Header.h桥接头文件如图下图:

这里写图片描述

当然你也可以在Building Settings中自己设置桥接头文件,如下图:

这里写图片描述

创建好OC_Swift-Bridging-Header.h文件后,在OC_Swift-Bridging-Header.h文件中即可import需要提供给Swift的Objective-C头文件,Swift即可调用对应的Objective-C文件。同时Xcode可以自动生成Objective-C对应的Swift接口。

( PS:Objective-C类、协议、属性、方法、扩展、闭包等所有功能都可以无缝地被转换为Swift接口被Swift文件所调用。)


  • Objc调用Swift

Xcode会自动为Project生成头文件以便在Objective-C中调用。在Objective-C类中调用Swift,只需要#import “productModuleName-Swift.h”即可调用,Xcode提供的头文件以Swift代码的模块名加上-Swift.h为命名。
(PS:我这有个通俗的理解方式,不喜勿喷,可能不专业,但是好理解。。 “productModuleName-Swift.h文件可以理解为:这个是Objective-C调用Swift的,你写的swift文件在这个文件里对外提供了OC使用的接口,OC调swift,引入这个文件,相当于直接可以使用对外接口了,你可以通俗理解 平常OC的.h文件留的接口)
在这个头文件中,将包含Swift提供给Objective-C的所有接口、Appdelegate及自动生成的一些宏定义。

在大部分情况下,Objective-C都可以无缝地调用Swift,但是由于Swift相对于Objective-C多了一些新特性,比如泛型、元组、枚举的等,所以Swift暴漏给Objective-C的接口多了一些限制,因此Swift只能暴露在Objective-C中有效的接口。

2017-03-02 16:41:58 Hello_Hwc 阅读数 11091

前言

为什么要写这样一篇文章,因为昨天和一个朋友讨论到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

OCSource.m

#import "OCSource.h"

@implementation OCSource

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

Swift调用OC

新建SwiftSource.swift

open class SwiftIt{
    public init(){}
    let ocObject = OCSource()
    public func encapsulate(){
        ocObject.functionFromOC()
    }
}

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

也就是,MixFramework.h,

#import <MixFramework/OCSource.h>

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

Boom~~~,编译不通过。

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

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

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

OC调用Swift

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

open class ClassForOC:NSObject{
    public static let textForOC = "textForOC"
}

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

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

@implementation OCSource

- (void)functionFromOC{
    NSLog(@"%@",[ClassForOC textForOC]);
}
@end

然后,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.
    }
}

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

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

嗯,framework打包成功了。


问题

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

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

    var s = OCSource()

也就是说,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()
}

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

import MixFramework.OCSource

优雅的解决方案

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

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


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

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

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

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

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


总结

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

Demo下载

2018-07-12 06:38:01 weixin_34179968 阅读数 26

Swift还在不断的优化,说开发效率因该是比OC更快的,毕竟很多代码格式都简化了,做了大量的瘦身。尽管如此,当前的许多公司的项目还是在使用OC来做,不过也不排除使用Swift替换的可能。说替换,有的项目太大,不能一次替换。就需要在OC里调用Swift代码,在Swift调用OC代码的混编模式了。今天,就简单说下基本的设置,以后会慢慢更新。

1.OC调用Swift

a.设置defines module 为Yes



b.创建Swift文件。ps: 1.不用创建桥接头文件 2.类一定要是公开的。



c.引入头文件。固定格式:#import "项目名-Swift.h"



2.Swift调用OC

a.创建桥接头文件(也可以在创建OC类的时候,会有弹出一个创建选项,选择创建)。

ps: 桥接头文件的格式:项目名-Bridging-Header




b.设置桥接头文件

1.设置头文件,如图?



2.引入OC的代码头文件






没有更多推荐了,返回首页