2017-11-18 14:35:08 chen_xi_hao 阅读数 836

ios中,swift与objc相互要相互调用的话,这里objc可以直接调用swift中的类和函数,但是swift没办法直接调用objc中的类和函数,这时候就需要用到桥接文件,在桥接文件里import进objc中类的头文件就可以。

具体操作如下:

如我们引入了objc的框架masonry,但是你的项目是swift的,这里就需要用到一个桥接文件,新建一个文件,选择header类型。

桥接文件名字随意,好像没什么限制,然后创建好之后,要在项目设置那里配置该文件,在Build Settings –>Objective-C Bridging Header这里写入桥接文件的路径。这样子就成功了,之后就在桥接文件引入objc类的头文件,swift里面就可以调用该类的函数和属性了。

以下是图解流程:
1、
这里写图片描述

2、
这里写图片描述

3、
这里写图片描述

4、
这里写图片描述

5、
这里写图片描述

6、
这里写图片描述

该文章没什么好讲的,操作简易,只是自己很久没操作就会忘记,特此记录一下。

QQ:361561789
有事可以直接加Q联系

2018-05-28 20:45:02 cewei711 阅读数 474

最近调试Swift时需要用到引用计数器,找了半天,在此记录

//swift中方法    
let count = CFGetRetainCount(self)//swift获取方法

//OC方法如下
//第一种方式,KVC
[obj valueForKey:@"retainCount"]  

//第二种方式,runTime
OBJC_EXTERN int _objc_rootRetainCount(id);  
_objc_rootRetainCount(obj) 

//第三种方式
CFGetRetainCount((__bridge CFTypeRef)(obj))  
 

2016-09-20 10:48:49 weixin_35755389 阅读数 1555

Swift 中 Selector 方法的访问权限控制问题

今天用Swift写了个视图,在视图上加个手势,如下所示:

1
2
panGestureRecognizer = UIPanGestureRecognizer(target: self, action: "beginDragged:")
addGestureRecognizer(panGestureRecognizer)

运行了下程序,然后崩溃了。崩溃日志如下:

1
[**.SwipeCardView beginDragged:]: unrecognized selector sent to instance 0x125e5bc10

而我已经在SwipeCardView类中定义了beginDragged:方法,如下所示:

1
2
3
private func beginDragged(gestureRecognizer: UIPanGestureRecognizer) {
  // ....
}

由于我并不想将beginDragged:方法暴露出去,所以将其定义为一个private方法。方法的定义一切正常,手势的Selector方法也设置正常,却报了未找到方法的异常。那问题可能就应该在访问权限问题上了。

我们知道Selector是Objective-C的产物,它用于在运行时作为一个键值去找到对应方法的实现。一个Objective-C的方法是由objc_method结束体定义的,其声明如下:

1
2
3
4
5
struct objc_method {
    SEL method_name                    OBJC2_UNAVAILABLE;  // 方法名
    char *method_types                  OBJC2_UNAVAILABLE;
    IMP method_imp                      OBJC2_UNAVAILABLE;  // 方法实现
}

这就要求selector引用的方法必须对ObjC运行时是可见的。而Swift是静态语言,虽然继承自NSObject的类默认对ObjC运行时是可见的,但如果方法是由private关键字修饰的,则方法默认情况下对ObjC运行时并不是可见的,所以就导致了以上的异常:运行时并没找到SwipeCardView类的beginDragged:方法。

所以,我们必须将private修饰的方法暴露给运行时。正确的做法是在 private 前面加上 @objc 关键字,这样就OK了。

1
2
3
@objc private func beginDragged(gestureRecognizer: UIPanGestureRecognizer) {
  // ....
}

另外需要注意的是,如果我们的类是纯Swift类,而不是继承自NSObject,则不管方法是private还是internal或public,如果要用在Selector中,都需要加上@objc修饰符。

2014-07-29 18:59:28 zhangao0086 阅读数 58873

一般来说我们总会在设置Block之后,在合适的时间回调Block,而不希望回调Block的时候Block已经被释放了,所以我们需要对Block进行copy,copy到堆中,以便后用。

当一个Block被Copy的时候,如果你在Block里进行了一些调用,那么将会有一个强引用指向这些调用方法的调用者,有两个规则:

  • 如果你是通过引用来访问一个实例变量,那么将强引用至self
  • 如果你是通过值来访问一个实例变量,那么将直接强引用至这个“值”变量
苹果官方文档里有两个例子来说明这两种情况:

上面第一种情况相当于用self.xxx来访问实例变量,所以强引用指向了self;第二种情况把实例变量变成了本地临时变量,强引用将直接指向这个本地的临时变量。大多数情况下,我们只用处理第一种情况就行了,因为第二种情况虽然会造成循环引用,但是临时变量很快就被释放了,不会造成真正的循环引用。要避免强引用到self的话,用__weak把self重新引用一下就行了,像这样:
__weak ViewController *weakSelf = self;

2017-06-18 23:07:05 madaxin 阅读数 1407

 

快速起步

你可以在 xcode 里同时使用 Swift 和 Objective-C(以下简称OC)来写代码,混搭编程的好处很多,比如允许大量代码的复用,在性能和开发效率之间找到平衡等。

在 Swift 中引用 OC

我们建立一个工程时,XCode会询问我们选择什么语言进行开发,如果你选择的是OC,那么当你第一次新建一个swift文件时,开发环境会询问你是否建立一个 .h 文件。这个 .h 文件命名方式是 "#ProjectName#-Bridging-Header.h" 。你可以让开发环境帮你创建这个文件,也可以自己建,编译器只认这个文件名,只要别写错就好。

我们称这个文件叫桥接文件,它的作用是把OC代码选择性的暴露给swift,让swift可以调用这些接口。

暴露的方式是通过import,也就是说,你可以在这个 .h 文件里 import 任何你想要暴露给swift的代码,然后就可以在 swift 中访问了。

动手实践:

  1. 打开xcode,创建一个OC工程 HelloWorld
  2. 创建一个叫 HelloOC 的 OC 类,实现静态方法 hello,实现代码 NSLog("hello, OC.")
  3. 创建一个叫 HelloSwift 的 swift 类,继承NSObject,实现静态函数 hello(),实现代码 NSLog("hello, swift.")
  4. 这时候 xcode 会弹出询问是否创建文件 HelloWorld-Bridging-Header.h ,选择是,如果你点了否,就自己创建一个
  5. 在 HelloWorld-Bridging-Header.h 代码里,加入 #import "HelloOC.h"
  6. 在HelloSwift 的 hello 函数里,在 NSLog("hello, swift.") 后追加 HelloOC.hello()

 

注意,继承自 NSObject 这点很重要,因为OC所有类都是继承自 NSObject,而 swift 没有这个要求,所以如果需要暴露 swift 的类给 OC ,一定必须是 NSObject 的子类才行。

如果编译成功了,那就说明编译器允许让你通过 HelloSwift 调用 HelloOC 的代码了。

这时候执行程序,会发现输出终端并没有打印任何东西。因为程序主体本身并没有调用 HelloSwift,我们建立的是 OC 工程,所以这时候就需要 OC 来调用 swift代码了。

在 OC 中引用 swift

当我们建立 HelloSwift 时,xcode 其实做了一些后台工作,除了询问你是否建立 "HelloWorld-Bridging-Header.h" 外,它还隐式的创建了一个叫 "HelloWorld-Swift.h" 的头文件,记住,这个文件是 xcode 隐式创建的,所以不要自己去建立这个文件,很多人查资料发现需要这个头文件没看仔细就自己去创建,结果导致各种编译不通过。

这个 HelloWorld-Swift 文件从文件到代码都是 xocode 动态生成的,你不需要编辑它,如果感兴趣里面到底写了什么,你可以通过 import 这个文件,Jump To Definition 的方式一探究竟。

当你需要暴露 swift 的类给 OC 调用时,你不需要通过任何逐个 import 的方式,你只要 import "HelloWorld-Swift.h" 即可。

尝试步骤如下:

  1. 在 ViewController.m 文件中,引入头文件 #import "HelloWorld-Swift.h"
  2. 在 ViewDidLoad 方法的实现中,调用 [HelloSwift hello];

这时候编译,执行,工程打印日志输出为:

Hello, Swift.
Hello, OC.

框架(framework)的引用

开发项目经常要引用第三方框架,在 swift 中,引用这些框架是非常简单的,只要在 HelloWorld-Bridging-Header.h 中用 @import 语句包含该框架即可。不管该框架是用什么 swift 还是 OC 写的,又或者是混合编写,用法都一样。

而如果是用 OC 引用这些框架的话,标准做法应该是:

  1. 在 .m 文件中,用 @import 语句引用该框架
  2. 在 .h 文件中,如果需要在接口中声明对应的类,则应该用 @class 做前置声明,用这样的做法来规避循环引用问题。

举例 HelloWorld 项目来说,当我们要在 HelloSwift.swift 中引用一个 SwiftFrameWork 框架时,正确的做法是:

  1. 在 HelloWorld-Bridging-Header.h 中加入 @import SwiftFrameWork;
  2. 在 HelloSwift.swift 中自由调用 SwiftFrameWork 的类。

而如果要在 HelloOC.h 和 HelloOC.m 中这么做,则标准做法应该是:

  1. 在 HelloOC.m 中,通过 @import SwiftFrameWork;
  2. 在 HelloOC.h 中,如果有需要引用到的 SwiftFrameWork 框架中的类,用前置声明的方法解决,比如如果需要引用类 ClassA,则可以在引用前声明 @class ClassA;
  3. 如果需要在 HelloOC.h 中引用到 HelloSwift 类,也应该遵循步骤 2 的做法。

protocol (协议)

对于swift 的 protocol,也可以暴露给 OC 调用,但是需要做一些额外的工作,需要针对要暴露的 swift protocol 添加 @objc 声明,并且对于 optional 函数也要追加 @objc @optional

在 HelloSwift.swift 追加协议代码:

// 因为这个 protocol 要暴露给 OC 用,所以用 @objc 声明
@objc protocol HelloProtocol {
    // 这是一个普通的swift协议函数
    func protocolFunction()
    // 这是个 optional 函数,需要在前面追加 @objc 声明
    @objc optional func optionalProtocolFunction()
}
    

一旦完成了以上操作,OC类即可声明和实现对应的协议函数为其他类提供回调实现。

错误码

swift 和 OC 之间的错误码共享方案很简单,就是简单的命名映射技术,在 swift 中定义错误码如下:

@objc public enum CustomError: Int, Error {
    case a, b, c
}
    

则 xcode 会在 HelloWorld-Swift.h 中声明对应的面向 OC 的错误码:

typedef SWIFT_ENUM(NSInteger, CustomError) {
    CustomErrorA = 0,
    CustomErrorB = 1,
    CustomErrorC = 2,
};
static NSString * _Nonnull const CustomErrorDomain = @"HelloWorld.CustomError";
    

命名映射的规则比较简单明了,Enum 类型名不变,实例的名称通过大骆驼命名法进行拼接。

 

其它

 

 

苹果为保证 swift 和 OC 顺利交互,做了大量严谨的工作,这里就不一一说明了,毕竟道理大同小异,在需要的时候查阅文档就可以了,类似需要查阅的知识点有:

  • 用 NS_REFINED_FOR_SWIFT 宏重定义 OC 接口
  • 手动为 swift 类指定一个映射名给 OC 调用(通过 @objc)
  • 通过 NS_SWIFT_NAME 指定 swift 自定义名称
  • ...

参考资料

Using Swift with Cocoa and Objective-C (Swift 4)

  • author: Madaxin
  • email: madaxin@outlook.com
  • qq group: 527628370
  • home: madaxin.com

 

swift调用第三方oc库

阅读数 1060

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