swift和objc混编

1. swift中默认的属性为strong类型,如果需要定义weak类型的话就必须显示地指出weak。

2. swift中没有readonly和read-write类型。let定义的常量就是readonly类型,var定义的变量就是read-write类型的

3. 使用@objc来声明swift书写的方法等可以直接被objc来使用。其中包含的情况为:

 

  • 未嵌套的类
  • 协议
  • 非泛型枚举(仅限于原始值为整形的类型)
  • 类和协议中的属性和方法
  • 构造器和析构器
  • 下标

 

我们逐个来看看实际的使用:

[objc] view plain copy

  1. @objc class MyHelper:NSObject {  
  2.     // class code  
  3. }  

Objective-C 中所有的类都需要继承自NSObject,Swift 中的类需要供 Objective-C 调用的时候,自然也需要显式继承自NSObject。当然,你也可以继承所有 Objective-C 中的类,因为他们本身也继承自NSObject

 

 

[objc] view plain copy

 

  1. @objc class MyViewController : UIViewController {  
  2.       
  3. }  

 

另外一个细节是,Swift 中的类名,可以使用中文命名,而 Objective-C 中的却只能使用 ASCII 码,在使用@objc时,需要指定 Objective-C 中使用的 ASCII 名称。这个知识点请参见喵神的 tips

 

[objc] view plain copy

  1. @objc(MyClass)  
  2. class 我的类: NSObject {  
  3.     @objc(greeting:)  
  4.     func 打招呼(名字: String) {  
  5.         print("哈喽,\(名字)")  
  6.     }  
  7. }  

协议

 

 

@objc修饰协议与修饰类一样,需要注意的是,如果协议中有optional修饰的方法,就必须使用@objc来修饰:

[objc] view plain copy

  1. @objc protocol CounterDataSource {  
  2.     optional func incrementForCount(count: Int) -> Int  
  3.     optional var fixedIncrement: Int { get }  
  4. }  

 

关于可选协议的描述,可以参见官方教程

 

枚举

Swift 中的枚举类型,功能增强了不少。Objective-C 中还是传统的枚举类型,必须使用整型作为原始值。这样看来,Swift 中的枚举类型如果要被@objc修饰,则需要满足原始值是整型的限制条件。不然就会报编译错误。
关于如何在 Objective-C 中使用 Swift 枚举类型,可以见这个帖子:

[objc] view plain copy

  1. // Swift  
  2. @objc enum Bear: Int {  
  3.     case Black, Grizzly, Polar  
  4. }  
  5.   
  6. // OC   
  7. Bear type = BearBlack;  
  8. switch (type) {  
  9.     case BearBlack:  
  10.     case BearGrizzly:  
  11.     case BearPolar:  
  12.        [self runLikeHell];  
  13. }  

 

 

其他

 

 

在类和协议中的属性和方法,构造器和析构器,下标中使用@objc修饰的用法与上面的用法一样。这里举一个官网的例子说明:

[objc] view plain copy

  1. @objc class ExampleClass: NSObject {  
  2.     var enabled: Bool {  
  3.         @objc(isEnabled) get {  
  4.             // Return the appropriate value  
  5.         }  
  6.     }  
  7. }  

 

需要注意的是,如果类中方法或者属性被@objc修饰,那么类就必须被@objc修饰。

 

stackoverflow 相关问题整理

swift自动地将一些objc类型转换成swift类型,将一些swift类型转换成了objc类型。类型可以在objc和swift之间进行转换。例如,swift中,你传递了一个string类型的值给一个objc方法,这个objc方法声明接收nsstring类型的参数。除了这个,许多cocoa框架,包括foundation, appkit, 和uikit。例如,nscoder方法decodeObjectOfClass(_:forKey:)使用swift来提供一个更强大功能的类型签名。

桥接类型

 

Objective-C Reference Type

 

Swift Value Type

NSAffineTransform

AffineTransform

NSArray

Array

NSCalendar

Calendar

NSCharacterSet

CharacterSet

NSData

Data

NSDateComponents

DateComponents

NSDateInterval

DateInterval

NSDate

Date

NSDecimalNumber

Decimal

NSDictionary

Dictionary

NSIndexPath

IndexPath

NSIndexSet

IndexSet

NSLocale

Locale

NSMeasurement

Measurement

NSNotification

Notification

NSNumber

Swift numeric types (Int, Float, and so on.)

NSPersonNameComponents

PersonNameComponents

NSSet

Set

NSString

String

NSTimeZone

TimeZone

NSURLComponents

URLComponents

NSURLQueryItem

URLQueryItem

NSURL

URL

NSURLComponents

URLComponents

NSURLQueryItem

URLQueryItem

NSURLRequest

URLRequest

NSUUID

UUID

如下:

import UIKit
import Foundation

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        //objc和swift系统的api和类型可以互转使用
        let string: String = "abc"
        let bridgedString: NSString = string as NSString
        NSLog("the string value is %@", bridgedString);
        
        let stringLiteral: NSString = "123"
        if let integerValue = Int(stringLiteral as String) {
            print("\(stringLiteral) is the integer \(integerValue)")
        }
        
        // 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.
    }
}

 

Swift and Objective-C in the Same Project

swift和objc的兼容性时的你可以创建包含两种语言文件的工程。你可以使用这个特点,叫做mix和match来编写app。

Mix and Match Overview

objc和swift文件可以在一个工程中兼容存在。你只需要简单地添加一个文件或者其他语言到现有的工程中即可。这个流程创建了mixed language 和框架。

Importing Code from Within the Same App Target

你可以会在objc中访问swift或者在swift文件中访问objc。这个处理应用于non-framework targets。

Importing Objective-C into Swift

为了在同一个app target中import一系列的objc文件到你的swift代码中,你以来objc桥接header来将这些文件暴露给swift。xcode在你将swift文件添加进objc app或者将objc文件添加到swift app时会提供创建这样一个头文件。

 

如果你接受了,xcode就会创建这个头文件并且以你的product module名字+“-Bridging-Header.h”的形式来新建。

你也可以自己通过File > New > File > (iOS, watchOS, tvOS, or macOS) > Source > Header File.的方式来添加

你需要编辑这个桥接头文件来把你的objc代码暴露给你的swift代码。

To import Objective-C code into Swift from the same target

  1. 在你的objc桥接头文件中,import每一个你想要暴露给swift的头文件,例如:

    1. #import "XYZCustomCell.h"
    2. #import "XYZCustomView.h"
    3. #import "XYZCustomViewController.h"
  2. 在swift compiler - code generation中,确保objc bridging header 设置下有一个指向bridging header file的路径。

    这个路径需要是相对的,类似于在你的info.plist文件中指定的形式。多数情况下你不需要修改这个设置

任何公共的objc头文件都需要罗列在这个桥接文件中。objc功能会自动在target中在任何的swift文件中可用。而且不需要再import声明。

  1. let myCell =XYZCustomCell()
  2. myCell.subtitle ="A custom cell"

总结:

1.xcode会在你试图做mix的时候,创建一个product module名字+“-Bridging-Header.h”的文件

2.在这个文件中import进你想要访问的objc头文件

3.在swift文件中就可以访问到objc文件中的方法

Importing Swift into Objective-C

当你把swift代码import到objective c中时,你依赖的是xcode产生的header file来把这些文件暴露给objective c。这个自动生成的文件是一个objective c头文件声明了你target中的swift接口。这个头文件的名称就是你的产品模块名称加上-Swift.h后缀。

注意:不论你初始创建的是swift还是objective c的工程,其实xcode都已经为你自动创建好了这个头文件。不过有的时候需要反复clean几次后再build才能编译上。否则会运行时出错。

To import Swift code into Objective-C from the same target

  • Import the Swift code from that target into any Objective-C .m file within that target using this syntax and substituting the appropriate name:

    1. #import "ProductModuleName-Swift.h" 在你想要访问swift的某个objc文件中首先import这个自动生成的头文件。然后就可以访问对应的swift中的方法了。

The Swift files in your target will be visible in Objective-C .m files containing this import statement. For information on using Swift from Objective-C code, seeUsing Swift from Objective-C.

 
 

Import into Swift

Import into Objective-C

Swift code

No import statement

#import "ProductModuleName-Swift.h"

Objective-C code

No import statement; Objective-C bridging header required

#import "Header.h"

总结:

1.不论初始创建的什么类型的工程,xcode已经自动创建好了"ProductModuleName-Swift.h"的头文件

2.只要在需要使用swift的objc文件中import这个自动生成的头文件就可以访问swift中的方法了

3.swif中的类最终必须集成于 nsobject,否则调用时运行出错

4.自动生成的这个头文件可能需要一定时间生成,因此会出现访问不到的情况,需要多次clean后编译

Importing Code from Within the Same Framework Target

如果你正在写一个mixed语言的框架,你可能需要在swift中访问objective c并且在objective c中使用swift。

Importing Objective-C into Swift

为了将一系列的objective c文件导入到你的swift代码中,你需要将这些文件导入到objc的unbrella头中去。

To import Objective-C code into Swift from the same framework

  1. Under Build Settings, in Packaging, make sure the Defines Module setting for that framework target is set to “Yes”.

  2. In your umbrella header file, import every Objective-C header you want to expose to Swift. For example:

    1. #import <XYZ/XYZCustomCell.h>
    2. #import <XYZ/XYZCustomView.h>
    3. #import <XYZ/XYZCustomViewController.h>

Swift will see every header you expose publicly in your umbrella header. The contents of the Objective-C files in that framework will be available in any Swift file within that framework target automatically, without any import statements. Use your custom Objective-C code with the same Swift syntax you use with system classes.

  1. let myOtherCell =XYZCustomCell()
  2. myOtherCell.subtitle ="Another custom cell"

Importing Swift into Objective-C

To import a set of Swift files in the same framework target as your Objective-C code, you don’t need to import anything into the umbrella header for the framework. Instead, import the Xcode-generated header file for your Swift code into any Objective-C .m file you want to use your Swift code from.

Because the generated header for a framework target is part of the framework’s public interface, only declarations marked with thepublic or open modifier appear in the generated header for a framework target.

Swift methods and properties that are marked with the internal modifier and declared within a class that inherits from an Objective-C class are accessible to the Objective-C runtime. However, they are not accessible at compile time and do not appear in the generated header for a framework target.

For more information on access-level modifiers, see Access Control in The Swift Programming Language (Swift 3.0.1).

To import Swift code into Objective-C from the same framework

  1. Under Build Settings, in Packaging, make sure the Defines Module setting for that framework target is set to “Yes”.

  2. Import the Swift code from that framework target into any Objective-C.m file within that framework target using this syntax and substituting the appropriate names:

    1. #import <ProductName/ProductModuleName-Swift.h>

The Swift files in your framework target will be visible in Objective-C.m files containing this import statement. For information on using Swift from Objective-C code, seeUsing Swift from Objective-C.

 
 

Import into Swift

Import into Objective-C

Swift code

No import statement

#import <ProductName/ProductModuleName-Swift.h>

Objective-C code

No import statement; Objective-C umbrella header required

#import "Header.h"

Importing External Frameworks

You can import external frameworks that have a pure Objective-C codebase, a pure Swift codebase, or a mixed-language codebase. The process for importing an external framework is the same whether the framework is written in a single language or contains files from both languages. When you import an external framework, make sure the Defines Module build setting for the framework you’re importing is set to “Yes”.

You can import a framework into any Swift file within a different target using the following syntax:

  1. import FrameworkName

You can import a framework into any Objective-C .m file within a different target using the following syntax:

  1. @importFrameworkName;
 
 

Import into Swift

Import into Objective-C

Any language framework

import FrameworkName

@import FrameworkName;

Using Swift from Objective-C

Once you import your Swift code into Objective-C, use regular Objective-C syntax for working with Swift classes.

  1. MySwiftClass *swiftObject = [[MySwiftClass alloc]init];
  2. [swiftObjectswiftMethod];

A Swift class must be a descendant of an Objective-C class to be accessible and usable in Objective-C. For more information about what you can access from Objective-C and how the Swift interface is imported, seeSwift Type Compatibility.

Referencing a Swift Class or Protocol in an Objective-C Header

为了避免循环引用,不要把swift代码import到objective c头文件中。相反的,你可以在objective c接口中预声明一个swift类或者协议。

  1. // MyObjcClass.h
  2. @class MySwiftClass;
  3. @protocol MySwiftProtocol;
  4.  
  5. @interface MyObjcClass :NSObject
  6. - (MySwiftClass*)returnSwiftClassInstance;
  7. - (id<MySwiftProtocol>)returnInstanceAdoptingSwiftProtocol;
  8. // ...
  9. @end

预声明swift类和协议仅仅能被用于方法类型和属性声明。

Declaring a Swift Protocol That Can Be Adopted by an Objective-C Class

声明一个可以被objective c类所使用的swift协议,关键是用@objc来声明这个协议可以被objective c来使用

  1. @objc public protocol MySwiftProtocol {
  2. func requiredMethod()
  3.  
  4. @objc optionalfunc optionalMethod()
  5. }

optional类型的protocol需要使用@objc来做修饰符

Adopting a Swift Protocol in an Objective-C Implementation

An Objective-C class can adopt a Swift protocol in its implementation (.m) file by importing the Xcode-generated header for Swift code and using a class extension.

 

  1. // MyObjcClass.m
  2. #import "ProductModuleName-Swift.h"
  3.  
  4. @interface MyObjcClass() <MySwiftProtocol>
  5. // ...
  6. @end
  7.  
  8. @implementation MyObjcClass
  9. // ...
  10. @end

Declaring a Swift Error Type That Can Be Used from Objective-C

Swift enumerations conforming to the Error protocol and declared with the@objc attribute produce an NS_ENUM declaration, as well as an NSString constant for the corresponding error domain in the generated header. For example, given the following Swift enumeration declaration:

  1. @objc publicenum CustomError: Int, Error {
  2. case a,b, c
  3. }

Here’s the corresponding Objective-C declaration in the generated header:

  1. // Project-Swift.h
  2. typedef SWIFT_ENUM(NSInteger,CustomError) {
  3. CustomErrorA = 0,
  4. CustomErrorB = 1,
  5. CustomErrorC = 2,
  6. };
  7. static NSString* const CustomErrorDomain= @"Project.CustomError";

Overriding Swift Names for Objective-C Interfaces

The Swift compiler automatically imports Objective-C code as conventional Swift code. It imports Objective-C class factory methods as Swift initializers, and Objective-C enumeration cases truncated names.

There may be edge cases in your code that are not automatically handled. If you need to change the name imported by Swift of an Objective-C method, enumeration case, or option set value, you can use theNS_SWIFT_NAME macro to customize how a declaration is imported.

Class Factory Methods

If the Swift compiler fails to identify a class factory method, you can use theNS_SWIFT_NAME macro, passing the Swift signature of the initializer to have it imported correctly. For example:

  1. + (instancetype)recordWithRPM:(NSUInteger)RPMNS_SWIFT_NAME(init(RPM:));

If the Swift compiler mistakenly identifies a method as a class factory method, you can use theNS_SWIFT_NAME macro, passing the Swift signature of the method to have it imported correctly. For example:

  1. + (id)recordWithQuality:(double)qualityNS_SWIFT_NAME(record(quality:));

Enumerations

By default, Swift imports enumerations by truncating enumeration value name prefixes. To customize the name of an enumeration case, you can use theNS_SWIFT_NAME macro, passing the Swift enumeration case name. For example:

  1. typedef NS_ENUM(NSInteger,ABCRecordSide) {
  2. ABCRecordSideA,
  3. ABCRecordSideB NS_SWIFT_NAME(FlipSide),
  4. };

Making Objective-C Interfaces Unavailable in Swift

Some Objective-C interfaces may not be suitable or necessary to be exposed as Swift interfaces. To prevent an Objective-C declaration from being imported by Swift, use theNS_SWIFT_UNAVAILABLE macro, passing a message directing API consumers to any alternatives that may exist.

For example, an Objective-C class providing a convenience initializer that takes variadic arguments for keys-value pairs may advise a Swift consumer to use a dictionary literal instead:

  1. + (instancetype)collectionWithValues:(NSArray*)values forKeys:(NSArray<NSCopying>*)keys NS_SWIFT_UNAVAILABLE("Use a dictionary literal instead");

Attempting to call the +collectionWithValues:forKeys: method from Swift code will result in a compiler error.

Refining Objective-C Declarations

You can use the NS_REFINED_FOR_SWIFT macro on an Objective-C method declaration to provide a refined Swift interface in an extension, while keeping the original implementation available to be called from the refined interface. For instance, an Objective-C method that takes one or more pointer arguments could be refined in Swift to return a tuple of values.

  • Initializer methods are imported by Swift with double underscores (__) prepended to their first argument labels.

  • Object subscripting methods are imported by Swift as methods with double underscores (__) prepended to their base names, rather than as a Swift subscript, if either the getter or setter method is marked asNS_REFINED_FOR_SWIFT.

  • Other methods are imported with double underscores (__) prepended to their base names.

Given the following Objective-C declarations:

  1. @interface Color :NSObject
  2.  
  3. - (void)getRed:(nullableCGFloat *)red
  4. green:(nullableCGFloat *)green
  5. blue:(nullableCGFloat *)blue
  6. alpha:(nullableCGFloat *)alphaNS_REFINED_FOR_SWIFT;
  7.  
  8. @end

You can provide a refined Swift interface in an extension like this:

  1. extension Color {
  2. var RGBA: (red:CGFloat, green: CGFloat,blue: CGFloat, alpha:CGFloat) {
  3. var r:CGFloat = 0.0
  4. var g:CGFloat = 0.0
  5. var b:CGFloat = 0.0
  6. var a:CGFloat = 0.0
  7. __getRed(red: &r,green: &g, blue: &b,alpha: &a)
  8. return (red:r, green: g,blue: b, alpha:a)
  9. }
  10. }

Naming Your Product Module

如果你的product name中含有.的话,它们会被替换成_.如果名称以数字为开头,那么第一个数字会被_来替换。可以在product module name build setting中自定义product module name并且使用这个自定义的name作为bridging和generated headers。

Note

You cannot override the product module name of a framework.

Troubleshooting Tips and Reminders

  • Treat your Swift and Objective-C files as the same collection of code, and watch out for naming collisions.

  • If you’re working with frameworks, make sure the Defines Module (DEFINES_MODULE) build setting under Packaging is set to “Yes”.

  • If you’re working with the Objective-C bridging header, make sure the Objective-C Bridging Header (SWIFT_OBJC_BRIDGING_HEADER) build setting under Swift Compiler - Code Generation is set to a path to the bridging header file relative to your project (for example, “MyApp/MyApp-Bridging-Header.h”).

  • Xcode uses your product module name (PRODUCT_MODULE_NAME)—not your target name (TARGET_NAME)—when naming the Objective-C bridging header and the generated header for your Swift code. For information on product module naming, see Naming Your Product Module.

  • To be accessible and usable in Objective-C, a Swift class must be a descendant of an Objective-C class or it must be marked@objc.

  • When you bring Swift code into Objective-C, remember that Objective-C won’t be able to translate certain features that are specific to Swift. For a list, seeUsing Swift from Objective-C.

  • If you use your own Objective-C types in your Swift code, make sure to import the Objective-C headers for those types before importing the Swift generated header into the Objective-C.m file you want to use your Swift code from.

  • Swift declarations marked with the private orfileprivate modifier do not appear in the generated header. Private declarations are not exposed to Objective-C unless they are explicitly marked with@IBAction, @IBOutlet, or@objc as well.

  • For app targets, declarations marked with the internal modifier appear in the generated header if the app target has an Objective-C bridging header.

  • For framework targets, only declarations with the public or open modifier appear in the generated header. You can still use Swift methods and properties that are marked with theinternal modifier from within the Objective-C part of your framework, as long they are declared within a class that inherits from an Objective-C class. For more information on access-level modifiers, seeAccess Control in The Swift Programming Language (Swift 3.0.1).

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值