oc swift 精确桥接_ios oc 桥接swift - CSDN
  • 前几天碰到客户有个神奇的要求:使用xcode8测试版,swift3.0开发一个项目,涉及到网络请求,...在swift项目中免不了要和oc进行混编,xcode7混编的时候很简单,直接托入一个oc类的文件,会提示你是否要创建桥接文件Bridg
    前几天碰到客户有个神奇的要求:使用xcode8测试版,swift3.0开发一个项目,涉及到网络请求,蓝牙,数据库等很多方面。这些用oc可以简单搞定的东西换成swift3.0后感觉整个人都不好了。本篇先说一下和OC交互的大致方法,稍后会边开发边写用法,大家一起交流。
    

    在swift项目中免不了要和oc进行混编,xcode7混编的时候很简单,直接拖入一个oc类的文件,会提示你是否要创建桥接文件BridgeHeader,现在xcode8则选择了无视,需要自己手动创建BridgeHeader文件并进行配置:


    1.直接在工程中command+n,出现如图,点击Header File创建桥接文件Bridging-Header.h,如图:




    2.点击next,出现如图画面,一定要记得勾选第一项,再点击create创建完成。




    3.配置桥接文件,点击target - build settings 通过搜索找到 Objective-C Bridging Header,配置一下文件路径即可,记得使用相对路径:$(SRCROOT),配置完成即可愉快的使用OC中的方法了。




    4.使用的时候按照如图的方式导入OC的.h文件即可使用。




    注意使用的时候要按照swift的方法调用oc类中的方法,会自动进行转换的。

    展开全文
  • OCSwift指南

    2020-03-10 00:01:09
    作者丨zhangferry来源丨iOS成长之路运行环境:Xcode 11.1 Swift5.0最近参与的一个项目需要从Objective-C(以下简称OC)转到Swift,期间遇到了一些...

    作者丨zhangferry

    来源丨iOS成长之路

    运行环境:Xcode 11.1 Swift5.0

    最近参与的一个项目需要从Objective-C(以下简称OC)转到Swift,期间遇到了一些坑,于是有了这篇总结性的文档。如果你也有将OC项目Swift化的需求,可以作为参考。

    OC转Swift有一个大前提就是你要对Swift有一定的了解,熟悉Swift语法,最好是完整看过一遍官方的Language Guide。

    转换的过程分自动化和手动转译,鉴于自动化工具的识别率不能让人满意,大部分情况都是需要手动转换的。

    自动化工具

    有一个比较好的自动化工具Swiftify,可以将OC文件甚至OC工程整个转成Swift,号称准确率能达到90%。我试用了一些免费版中的功能,但感觉效果并不理想,因为没有使用过付费版,所以也不好评价它就是不好。

    Swiftify还有一个Xcode的插件Swiftify for Xcode,可以实现对选中代码和单文件的转化。这个插件还挺不错,对纯系统代码转化还算精确,但部分代码还存在一些识别问题,需要手动再修改。

    手动Swift化

    桥接文件

    如果你是在项目中首次使用Swift代码,在添加Swift文件时,Xcode会提示你添加一个 .h的桥接文件。如果不小心点了不添加还可以手动导入,就是自己手动生成一个 .h文件,然后在 BuildSettings>SwiftCompiler-General>Objective-CBridgingHeader中填入该 .h文件的路径。

    这个桥接文件的作用就是供Swift代码引用OC代码,或者OC的三方库。

    #import "Utility.h"
    #import <Masonry/Masonry.h>
    

    BridgingHeader的下面还有一个配置项是 Objective-CGeneratedInterfaceHeaderName,对应的值是 ProjectName-Swift.h。这是由Xcode自动生成的一个隐藏头文件,每次Build的过程会将Swift代码中声明为外接调用的部分转成OC代码,OC部分的文件会类似 pch一样全局引用这个头文件。因为是Build过程中生成的,所以只有 .m文件中可以直接引用,对于在 .h文件中的引用下文有介绍。

    Appdelegate(程序入口)

    Swift中没有 main.m文件,取而代之的是 @UIApplicationMain命令,该命令等效于原有的执行 main.m。所以我们可以把 main.m文件进行移除。

    系统API

    对于 UIKit框架中的大部分代码转换可以直接查看系统API文档进行转换,这里就不过多介绍。

    property(属性)

    Swift没有 property,也没有 copynonatomic等属性修饰词,只有表示属性是否可变的 letvar

    注意点一OC中一个类分 .h.m两个文件,分别表示用于暴露给外接的方法,变量和仅供内部使用的方法变量。迁移到Swift时,应该将 .m中的property标为 private,即外接无法直接访问,对于 .h中的property不做处理,取默认的 internal,即同模块可访问。

    对于函数的迁移也是相同的。

    注意点二有一种特殊情况是在OC项目中,某些属性在内部( .m)可变,外部( .h)只读。这种情况可以这么处理:

    private(set) var value: String
    

    就是只对 valueset方法就行 private标记。

    注意点三Swift中针对空类型有个专门的符号 ?,对应OC中的 nil。OC中没有这个符号,但是可以通过在 nullablenonnull表示该种属性,方法参数或者返回值是否可以空。

    如果OC中没有声明一个属性是否可以为空,那就去默认值 nonnull

    如果我们想让一个类的所有属性,函数返回值都是 nonnull,除了手动一个个添加之外还有一个宏命令。

    NS_ASSUME_NONNULL_BEGIN
    /* code */
    NS_ASSUME_NONNULL_END
    

    enum(枚举)

    OC代码:

    typedef NS_ENUM(NSInteger, PlayerState) {
    PlayerStateNone= 0,
    PlayerStatePlaying,
    PlayerStatePause,
    PlayerStateBuffer,
    PlayerStateFailed,
    };
    typedef NS_OPTIONS(NSUInteger, XXViewAnimationOptions) {
    XXViewAnimationOptionNone= 1<<  0,
    XXViewAnimationOptionSelcted1= 1<<  1,
    XXViewAnimationOptionSelcted2= 1<<  2,
    }
    

    Swift代码

    enumPlayerState: Int{
    case none = 0
    case playing
    case pause
    case buffer
    case failed
    }
    structViewAnimationOptions: OptionSet{
    let rawValue: UInt
    staticletNone= ViewAnimationOptions(rawValue: 1<<0)
    staticletSelected1= ViewAnimationOptions(rawValue: 1<<0)
    staticletSelected2= ViewAnimationOptions(rawValue: 1<< 2)
    //...
    }
    

    Swift没有 NS_OPTIONS的概念,取而代之的是为了满足 OptionSet协议的 struct类型。

    懒加载

    OC代码:

    - (MTObject*)object{
    if(!_object) {
            _object = [MTObjectnew];
    }
    return _object;
    }
    

    Swift代码:

    lazy varobject: MTObject= {
    letobject= MTObject()
    return imagobjecteView
    }()
    

    闭包

    OC代码:

    typedefvoid(^DownloadStateBlock)(BOOL isComplete);
    

    Swift代码:

    typealias DownloadStateBlock= ((_ isComplete: Bool) -> Void)
    

    单例

    OC代码:

    + (XXManager*)shareInstance {
    staticdispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instance = [[self alloc] init];
    });
    return instance;
    }
    

    Swift对单例的实现比较简单,有两种方式:

    第一种

    swiftletshared=XXManager()// 声明在全局命名区(global namespace)ClassXXManager{}

    你可能会疑惑,为什么没有 dispatch_once,如何保证多线程下创建的唯一性?其实是这样的,Swift中全局变量是懒加载,在AppDelegate中被初始化,之后所有的调用都会使用该实例。而且全局变量的初始化是默认使用 dispatch_once的,这保证了全局变量的构造器(initializer)只会被调用一次,保证了 shard原子性

    第二种

    ClassXXManager{
    staticlet shared = XXManager()
    privateoverride init() {
    // do something
    }
    }
    

    Swift 2 开始增加了 static关键字,用于限定变量的作用域。如果不使用 static,那么每一个 shared都会对应一个实例。而使用 static之后, shared成为全局变量,就成了跟上面第一种方式原理一致。可以注意到,由于构造器使用了 private 关键字,所以也保证了单例的原子性。

    初始化方法和析构函数

    对于初始化方法OC先调用父类的初始化方法,然后初始自己的成员变量。Swift先初始化自己的成员变量,然后在调用父类的初始化方法。

    OC代码:

    // 初始化方法
    @interfaceMainView: UIView
    @property(nonatomic, strong) NSString*title;
    - (instancetype)initWithFrame:(CGRect)frame title:(NSString*)title NS_DESIGNATED_INITIALIZER;
    @end
    @implementationMainView
    - (instancetype)initWithFrame:(CGRect)frame title:(NSString*)title {
    if(self= [super initWithFrame:frame]) {
    self.title = title;
    }
    returnself;
    }
    @end
    // 析构函数
    - (void)dealloc {
    //dealloc
    }
    

    Swift代码:

    classMainViewSwift: UIView{
    let title: String
        init(frame: CGRect, title: String) {
    self.title = title
    super.init(frame: frame)
    }
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
    }
            deinit {
    //deinit
    }
    }
    

    函数调用

    OC代码:

    // 实例函数(共有方法)
    - (void)configModelWith:(XXModel*)model {}
    // 实例函数(私有方法)
    - (void)calculateProgress {}
    // 类函数
    + (void)configModelWith:(XXModel*)model {}
    

    Swift代码

    // 实例函数(共有方法)
    func configModel(with model: XXModel) {}
    // 实例函数(私有方法)
    private func calculateProgress() {}
    // 类函数(不可以被子类重写)
    static func configModel(with model: XXModel) {}
    // 类函数(可以被子类重写)
    class func configModel(with model: XXModel) {}
    // 类函数(不可以被子类重写)
    classfinal func configModel(with model: XXModel) {}
    

    OC可以通过是否将方法声明在 .h文件表明该方法是否为私有方法。Swift中没有了 .h文件,对于方法的权限控制是通过权限关键词进行的,各关键词权限大小为:private<fileprivate<internal<public<open

    其中 internal为默认权限,可以在同一 module下访问。

    NSNotification(通知)

    OC代码:

    // add observer
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(method) name:@"NotificationName"object:nil];
    // post
    [NSNotificationCenter.defaultCenter postNotificationName:@"NotificationName"object:nil];
    

    Swift代码:

    // add observer
    NotificationCenter.default.addObserver(self, selector: #selector(method), name: NSNotification.Name(rawValue: "NotificationName"), object: nil)
    // post
    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "NotificationName"), object: self)
    

    可以注意到,Swift中通知中心 NotificationCenter不带 NS前缀,通知名由字符串变成了 NSNotification.Name的结构体。

    改成结构体的目的就是为了便于管理字符串,原本的字符串类型变成了指定的 NSNotification.Name类型。上面的Swift代码可以修改为:

    extension NSNotification.Name{
    staticletNotificationName= NSNotification.Name("NotificationName")
    }
    // add observer
    NotificationCenter.default.addObserver(self, selector: #selector(method), name: .NotificationName, object: nil)
    // post
    NotificationCenter.default.post(name: .NotificationName, object: self)
    

    protocol(协议/代理)

    OC代码:

    @protocolXXManagerDelegate<NSObject>
    - (void)downloadFileFailed:(NSError*)error;
    @optional
    - (void)downloadFileComplete;
    @end
    @interfaceXXManager: NSObject
    @property(nonatomic, weak) id<XXManagerDelegate> delegate;
    @end
    

    Swift中对 protocol的使用拓宽了许多,不光是 class对象, structenum也都可以实现协议。需要注意的是 structenum为指引用类型,不能使用 weak修饰。只有指定当前代理只支持类对象,才能使用 weak。将上面的代码转成对应的Swift代码,就是:

    @objc protocol XXManagerDelegate{
        func downloadFailFailed(error: Error)
    @objc optional func downloadFileComplete() // 可选协议的实现
    }
    classXXManager: NSObject{
        weak vardelegate: XXManagerDelegate?
    }
    

    @objc是表明当前代码是针对 NSObject对象,也就是 class对象,就可以正常使用weak了。

    如果不是针对NSObject对象的delegate,仅仅是普通的class对象可以这样设置代理:

    protocol XXManagerDelegate: class{
        func downloadFailFailed(error: Error)
    }
    classXXManager{
        weak vardelegate: XXManagerDelegate?
    }
    

    值得注意的是,仅 @objc标记的 protocol可以使用 @optional

    Swift和OC混编注意事项

    函数名的变化

    如果你在一个Swift类里定义了一个delegate方法:

    @objc protocol MarkButtonDelegate{
        func clickBtn(title: String)
    }
    

    如果你要在OC中实现这个协议,这时候方法名就变成了:

    - (void)clickBtnWithTitle:(NSString*)title {
    // code
    }
    

    这主要是因为Swift有指定参数标签,OC却没有,所以在由Swift方法名生成OC方法名时编译器会自动加一些修饰词,已使函数作为一个句子可以"通顺"。

    在OC的头文件里调用Swift类

    如果要在OC的头文件里引用Swift类,因为Swift没有头文件,而为了让在头文件能够识别该Swift类,需要通过 @class的方法引入。

    @classSwiftClass;
    @interfaceXXOCClass: NSObject
    @property(nonatomic, strong) SwiftClass*object;
    @end
    

    对OC类在Swift调用下重命名

    因为Swift对不同的module都有命名空间,所以Swift类都不需要添加前缀。如果有一个带前缀的OC公共组件,在Swift环境下调用时不得不指定前缀是一件很不优雅的事情,所以苹果添加了一个宏命令 NS_SWIFT_NAME,允许在OC类在Swift环境下的重命名:

    NS_SWIFT_NAME(LoginManager)
    @interfaceXXLoginManager: NSObject
    @end
    

    这样我们就将 XXLoginManager在Swift环境下的类名改为了 LoginManager

    引用类型和值类型

    • struct 和 enum 是值类型,类 class 是引用类型。

    • String, Array和 Dictionary都是结构体,因此赋值直接是拷贝,而 NSStringNSArray 和 NSDictionary则是类,所以是使用引用的方式。

    • struct 比 class 更“轻量级”, struct 分配在栈中, class 分配在堆中。

    id类型和AnyObject

    OC中 id类型被Swift调用时会自动转成 AnyObject,他们很相似,但却其实概念并不一致。Swift中还有一个概念是 Any,他们三者的区别是:

    • id 是一种通用的对象类型,它可以指向属于任何类的对象,在OC中即是可以代表所有继承于 NSObject的对象。

    • AnyObject可以代表任何 class类型的实例。

    • Any可以代表任何类型,甚至包括 func类型。

    从范围大小比较就是:id<AnyObject<Any

    其他语法区别及注意事项(待补充)

    1、Swift语句中不需要加分号 ;

    2、关于Bool类型更加严格,Swift不再是OC中的非0就是真,真假只对应 truefalse

    3、Swift类内一般不需要写 self,但是闭包内是需要写的。

    4、Swift是强类型语言,必须要指定明确的类型。在Swift中 IntFloat是不能直接做运算的,必须要将他们转成同一类型才可以运算。

    5、Swift抛弃了传统的 ++--运算,抛弃了传统的C语言式的 for循环写法,而改为 for-in

    6、Swift的 switch操作,不需要在每个case语句结束的时候都添加 break

    7、Swift对 enum的使用做了很大的扩展,可以支持任意类型,而OC枚举仅支持 Int类型,如果要写兼容代码,要选择Int型枚举。

    8、Swift代码要想被OC调用,需要在属性和方法名前面加上 @objc

    9、Swift独有的特性,如泛型, struct,非Int型的 enum等被包含才函数参数中,即使添加 @objc也不会被编译器通过。

    10、Swift支持重载,OC不支持。

    11、带默认值的Swift函数再被OC调用时会自动展开。

    语法检查

    对于OC转Swift之后的语法变化还有很多细节值得注意,特别是对于初次使用Swift这门语言的同学,很容易遗漏或者待着OC的思想去写代码。这里推荐一个语法检查的框架SwiftLint,可以自动化的检查我们的代码是否符合Swift规范。

    可以通过 cocoapods进行引入,配置好之后,每次 Build的过程,Lint脚本都会执行一遍Swift代码的语法检查操作,Lint还会将代码规范进行分级,严重的代码错误会直接报错,导致程序无法启动,不太严重的会显示代码警告(⚠️)。

    如果你感觉SwiftLint有点过于严格了,还可以通过修改 .swiftlint.yml文件,自定义属于自己的语法规范。

    近期精彩内容推荐:  

     有个程序媛上司是什么体验

     一个天才程序员的黑帮大佬人生

     200行Python代码做一个换脸程序

     在 IntelliJ IDEA 中使用 Git,太方便了!

    在看点这里好文分享给更多人↓↓

    展开全文
  • 在使用Swift进行iOS开发的过程中,经常涉及到SwiftOC混编的情况,有时主工程是OC的需要另外编入Swift代码,而有时主工程是Swift的需要另外编入OC代码。这其中涉及到修改一下XCode的工程配置,还有一些其他细节,...

    级别: ★★☆☆☆
    标签:「iOS」「Swift 」「Swift与OC混编」
    作者: dac_1033
    审校: QiShare团队


    在使用Swift进行iOS开发的过程中,经常涉及到Swift与OC混编的情况,有时主工程是OC的需要另外编入Swift代码,而有时主工程是Swift的需要另外编入OC代码。这其中涉及到修改一下XCode的工程配置,还有一些其他细节,下面我们就来介绍一下。

    1. 在同一个工程中的混编

    Swift 5.1中,两种混编的实现步骤:
    Swift访问OC:只需要在桥接文件(ProductName-Bridging-Header.h)中导入需要暴露给Swift的OC类,即可在Swift中访问相应OC类及方法。
    OC访问Swift:在OC类中导入ProductName-Swift.h文件(Target名称不同,对应文件名称也不同,工程配置中能看到),即可访问Swift中暴露给OC的属性和方法。

    1.1 Swift访问OC

    这篇文章中,我们以一个OC工程为宿主。我们实现一下在Swift类中访问OC,首先,创建一个空工程:

    在工程中创建一个Swift类:

    由XCode引导而创建桥接文件:

    在桥接文件中导入OC类头文件:

    我们就可以在宿主工程的这个Swift中直接使用OC类了:

    import UIKit
    
    class SwiftClass01: NSObject {
    
        var con:ViewController?
        
        override init() {
            super.init()
            
            self.con = ViewController()
        }
    }
    复制代码

    ###### 1.2 OC访问Swift

    我们再来看一下在这个宿主工程中,OC类中访问Swift,在工程配置的Build Settings中搜索Swift Compiler,可以看到Swift与OC混编的两个配置文件:

    在想要访问Swift方法的OC类中导入ProductName-Swift.h(手动输入没有提示,并且在编译之前报红),然后编译一下:

    即可在ViewController这个OC类中调用Swift:

    本例中,点入头文件QiHybridCompile-Swift.h,在工程里看一下他的定义:

    1. Swift类中,凡是允许OC访问的方法,方法前都要加@objc;
    2. Swift类中用public修饰过的方法,才会出现在ProductName-Swift.h文件中;
    3. 所有Swift类在ProductName-Swift.h文件都会被自动注册,以会自动@interface修饰,ProductName-Swift.h文件会自动更新。

    2. framework和宿主APP之间的混编

    首先,创建一个封装framework的Swift工程,名为"QiSwiftSdk.xcodeproj",并将它拖进宿主工程中。然后,在宿主工程配置中的BuildPhase下,设置工程依赖关系,如下图:

    本例中,在OC的宿主工程中创建一个Swift类"QSSdkTest",并写了两个测试方法,则调用Swift库时的代码如下:

    1. Swift库中所要暴露的类,类前需要使用关键字open修饰;
    2. Swift库某个类中供OC调用的方法,依然要用@objc public修饰;
    3. 本例默认的头文件"QiSwiftSdk.h"中,没有做任何操作;
    4. Swift库中也可以混编,Swift库的工程配置中也桥接文件的相关配置。

    小编微信:可加并拉入《QiShare技术交流群》。

    关注我们的途径有:
    QiShare(简书)
    QiShare(掘金)
    QiShare(知乎)
    QiShare(GitHub)
    QiShare(CocoaChina)
    QiShare(StackOverflow)
    QiShare(微信公众号)

    推荐文章:
    iOS UI状态保存和恢复(三)
    iOS UI状态保存和恢复(二)
    iOS UI状态保存和恢复(一)
    iOS 中精确定时的常用方法
    Sign In With Apple(一)
    算法小专栏:动态规划(一)
    Dart基础(一)
    Dart基础(二)
    Dart基础(三)
    Dart基础(四)
    奇舞周刊

    转载于:https://juejin.im/post/5d5a399a6fb9a06af50fca2b

    展开全文
  • OC项目转Swift指南

    2020-07-11 15:07:53
    OCSwift有一个大前提就是你要对Swift有一定的了解,熟悉Swift语法,最好是完整看过一遍官方的Language Guide。 转换的过程分自动化和手动转译,鉴于自动化工具的识别率不能让人满意,大部分情况都是需要手动转换的...

    运行环境:Xcode 11.1 Swift5.0

    最近参与的一个项目需要从Objective-C(以下简称OC)转到Swift,期间遇到了一些坑,于是有了这篇总结性的文档。
    如果你也有将OC项目Swift化的需求,可以作为参考。

    OC转Swift有一个大前提就是你要对Swift有一定的了解,熟悉Swift语法,最好是完整看过一遍官方的Language Guide

    转换的过程分自动化和手动转译,鉴于自动化工具的识别率不能让人满意,大部分情况都是需要手动转换的。

    自动化工具

    有一个比较好的自动化工具Swiftify,可以将OC文件甚至OC工程整个转成Swift,号称准确率能达到90%。我试用了一些免费版中的功能,但感觉效果并不理想,因为没有使用过付费版,所以也不好评价它就是不好。

    Swiftify还有一个Xcode的插件Swiftify for Xcode,可以实现对选中代码和单文件的转化。这个插件还挺不错,对纯系统代码转化还算精确,但部分代码还存在一些识别问题,需要手动再修改。

    手动Swift化

    桥接文件

    如果你是在项目中首次使用Swift代码,在添加Swift文件时,Xcode会提示你添加一个.h的桥接文件。如果不小心点了不添加还可以手动导入,就是自己手动生成一个.h文件,然后在Build Settings > Swift Compiler - General > Objective-C Bridging Header中填入该.h文件的路径。

    这个桥接文件的作用就是供Swift代码引用OC代码,或者OC的三方库。

    #import "Utility.h"
    #import <Masonry/Masonry.h>
    复制代码
    

    Bridging Header的下面还有一个配置项是Objective-C Generated Interface Header Name,对应的值是ProjectName-Swift.h。这是由Xcode自动生成的一个隐藏头文件,每次Build的过程会将Swift代码中声明为外接调用的部分转成OC代码,OC部分的文件会类似pch一样全局引用这个头文件。因为是Build过程中生成的,所以只有.m文件中可以直接引用,对于在.h文件中的引用下文有介绍。

    Appdelegate(程序入口)

    Swift中没有main.m文件,取而代之的是@UIApplicationMain命令,该命令等效于原有的执行main.m。所以我们可以把main.m文件进行移除。

    系统API

    对于UIKit框架中的大部分代码转换可以直接查看系统API文档进行转换,这里就不过多介绍。

    property(属性)

    Swift没有property,也没有copynonatomic等属性修饰词,只有表示属性是否可变的letvar

    注意点一 OC中一个类分.h.m两个文件,分别表示用于暴露给外接的方法,变量和仅供内部使用的方法变量。迁移到Swift时,应该将.m中的property标为private,即外接无法直接访问,对于.h中的property不做处理,取默认的internal,即同模块可访问。

    对于函数的迁移也是相同的。

    注意点二 有一种特殊情况是在OC项目中,某些属性在内部(.m)可变,外部(.h)只读。这种情况可以这么处理:

    private(set) var value: String
    复制代码
    

    就是只对valueset方法就行private标记。

    注意点三 Swift中针对空类型有个专门的符号?,对应OC中的nil。OC中没有这个符号,但是可以通过在nullablenonnull表示该种属性,方法参数或者返回值是否可以空。

    如果OC中没有声明一个属性是否可以为空,那就去默认值nonnull

    如果我们想让一个类的所有属性,函数返回值都是nonnull,除了手动一个个添加之外还有一个宏命令。

    NS_ASSUME_NONNULL_BEGIN
    /* code */
    NS_ASSUME_NONNULL_END
    复制代码
    

    这是我的iOS开发交流群:519832104不管你是小白还是大牛欢迎入驻,可以一起分享经验,讨论技术,共同学习成长!
    另附上一份各好友收集的大厂面试题,需要iOS开发学习资料、面试真题,进群即可获取!

    点击此处,立即与iOS大牛交流学习

    enum(枚举)

    OC代码:

    typedef NS_ENUM(NSInteger, PlayerState) {
        PlayerStateNone = 0,
        PlayerStatePlaying,
        PlayerStatePause,
        PlayerStateBuffer,
        PlayerStateFailed,
    };
    
    typedef NS_OPTIONS(NSUInteger, XXViewAnimationOptions) {
        XXViewAnimationOptionNone            = 1 <<  0,
        XXViewAnimationOptionSelcted1      	 = 1 <<  1,
        XXViewAnimationOptionSelcted2      	 = 1 <<  2,
    }
    复制代码
    

    Swift代码:

    enum PlayerState: Int {
        case none = 0
        case playing
        case pause
        case buffer
        case failed
    }
    struct ViewAnimationOptions: OptionSet {
        let rawValue: UInt
        static let None = ViewAnimationOptions(rawValue: 1<<0)
        static let Selected1 = ViewAnimationOptions(rawValue: 1<<0)
        static let Selected2 = ViewAnimationOptions(rawValue: 1 << 2)
        //...
    }
    复制代码
    

    Swift没有NS_OPTIONS的概念,取而代之的是为了满足OptionSet协议的struct类型。

    懒加载

    OC代码:

    - (MTObject *)object {
        if (!_object) {
            _object = [MTObject new];
        }
        return _object;
    }
    复制代码
    

    Swift代码:

    lazy var object: MTObject = {
        let object = MTObject()
        return imagobjecteView
    }()
    复制代码
    

    闭包

    OC代码:

    typedef void (^DownloadStateBlock)(BOOL isComplete);
    复制代码
    

    Swift代码:

    typealias DownloadStateBlock = ((_ isComplete: Bool) -> Void)
    复制代码
    

    单例

    OC代码:

    + (XXManager *)shareInstance {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instance = [[self alloc] init];
        });
        return instance;
    }
    复制代码
    

    Swift对单例的实现比较简单,有两种方式:

    第一种

    let shared = XXManager()// 声明在全局命名区(global namespace)
    Class XXManager { 
    }
    复制代码
    

    你可能会疑惑,为什么没有dispatch_once,如何保证多线程下创建的唯一性?其实是这样的,Swift中全局变量是懒加载,在AppDelegate中被初始化,之后所有的调用都会使用该实例。而且全局变量的初始化是默认使用dispatch_once的,这保证了全局变量的构造器(initializer)只会被调用一次,保证了shard原子性

    第二种

    Class XXManager {
    		static let shared = XXManager()
      	private override init() {
       		// do something 
        }
    }
    复制代码
    

    Swift 2 开始增加了static关键字,用于限定变量的作用域。如果不使用static,那么每一个shared都会对应一个实例。而使用static之后,shared成为全局变量,就成了跟上面第一种方式原理一致。可以注意到,由于构造器使用了 private 关键字,所以也保证了单例的原子性。

    初始化方法和析构函数

    对于初始化方法OC先调用父类的初始化方法,然后初始自己的成员变量。Swift先初始化自己的成员变量,然后在调用父类的初始化方法。

    OC代码:

    // 初始化方法
    @interface MainView : UIView
    @property (nonatomic, strong) NSString *title;
    - (instancetype)initWithFrame:(CGRect)frame title:(NSString *)title NS_DESIGNATED_INITIALIZER;
    @end
    
    @implementation MainView
    - (instancetype)initWithFrame:(CGRect)frame title:(NSString *)title {
        if (self = [super initWithFrame:frame]) {
            self.title = title;
        }
        return self;
    }
    @end
    // 析构函数
    - (void)dealloc {
        //dealloc
    }
    复制代码
    

    上面类在调用时

    Swift代码:

    class MainViewSwift: UIView {
        let title: String
        init(frame: CGRect, title: String) {
            self.title = title
            super.init(frame: frame)
        }
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    		deinit {
          //deinit
        }
    }
    复制代码
    

    函数调用

    OC代码:

    // 实例函数(共有方法)
    - (void)configModelWith:(XXModel *)model {}
    // 实例函数(私有方法)
    - (void)calculateProgress {}
    // 类函数
    + (void)configModelWith:(XXModel *)model {}
    复制代码
    
    // 实例函数(共有方法)
    func configModel(with model: XXModel) {}
    // 实例函数(私有方法)
    private func calculateProgress() {}
    // 类函数(不可以被子类重写)
    static func configModel(with model: XXModel) {}
    // 类函数(可以被子类重写)
    class func configModel(with model: XXModel) {}
    // 类函数(不可以被子类重写)
    class final func configModel(with model: XXModel) {}
    复制代码
    

    OC可以通过是否将方法声明在.h文件表明该方法是否为私有方法。Swift中没有了.h文件,对于方法的权限控制是通过权限关键词进行的,各关键词权限大小为: private < fileprivate < internal < public < open

    其中internal为默认权限,可以在同一module下访问。

    NSNotification(通知)

    OC代码:

    // add observer
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(method) name:@"NotificationName" object:nil];
    // post
    [NSNotificationCenter.defaultCenter postNotificationName:@"NotificationName" object:nil];
    复制代码
    

    Swift代码:

    // add observer
    NotificationCenter.default.addObserver(self, selector: #selector(method), name: NSNotification.Name(rawValue: "NotificationName"), object: nil)
    // post
    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "NotificationName"), object: self)
    复制代码
    

    可以注意到,Swift中通知中心NotificationCenter不带NS前缀,通知名由字符串变成了NSNotification.Name的结构体。

    改成结构体的目的就是为了便于管理字符串,原本的字符串类型变成了指定的NSNotification.Name类型。上面的Swift代码可以修改为:

    extension NSNotification.Name {
    	static let NotificationName = NSNotification.Name("NotificationName")
    }
    // add observer
    NotificationCenter.default.addObserver(self, selector: #selector(method), name: .NotificationName, object: nil)
    // post
    NotificationCenter.default.post(name: .NotificationName, object: self)
    复制代码
    

    protocol(协议/代理)

    OC代码:

    @protocol XXManagerDelegate <NSObject>
    - (void)downloadFileFailed:(NSError *)error;
    @optional
    - (void)downloadFileComplete;
    @end
    
    @interface XXManager: NSObject
    @property (nonatomic, weak) id<XXManagerDelegate> delegate;  
    @end
    复制代码
    

    Swift中对protocol的使用拓宽了许多,不光是class对象,structenum也都可以实现协议。需要注意的是structenum为指引用类型,不能使用weak修饰。只有指定当前代理只支持类对象,才能使用weak。将上面的代码转成对应的Swift代码,就是:

    @objc protocol XXManagerDelegate {
        func downloadFailFailed(error: Error)
        @objc optional func downloadFileComplete() // 可选协议的实现
    }
    class XXManager: NSObject {
    	weak var delegate: XXManagerDelegate?  
    }
    复制代码
    

    @objc是表明当前代码是针对NSObject对象,也就是class对象,就可以正常使用weak了。

    如果不是针对NSObject对象的delegate,仅仅是普通的class对象可以这样设置代理:

    protocol XXManagerDelegate: class {
        func downloadFailFailed(error: Error)
    }
    class XXManager {
    	weak var delegate: XXManagerDelegate?
    }
    复制代码
    

    值得注意的是,仅@objc标记的protocol可以使用@optional

    Swift和OC混编注意事项

    函数名的变化

    如果你在一个Swift类里定义了一个delegate方法:

    @objc protocol MarkButtonDelegate {
        func clickBtn(title: String)
    }
    复制代码
    

    如果你要在OC中实现这个协议,这时候方法名就变成了:

    - (void)clickBtnWithTitle:(NSString *)title {
    	// code
    }
    复制代码
    

    这主要是因为Swift有指定参数标签,OC却没有,所以在由Swift方法名生成OC方法名时编译器会自动加一些修饰词,已使函数作为一个句子可以"通顺"。

    在OC的头文件里调用Swift类

    如果要在OC的头文件里引用Swift类,因为Swift没有头文件,而为了让在头文件能够识别该Swift类,需要通过@class的方法引入。

    @class SwiftClass;
    
    @interface XXOCClass: NSObject
    @property (nonatomic, strong) SwiftClass *object;
    @end
    复制代码
    

    对OC类在Swift调用下重命名

    因为Swift对不同的module都有命名空间,所以Swift类都不需要添加前缀。如果有一个带前缀的OC公共组件,在Swift环境下调用时不得不指定前缀是一件很不优雅的事情,所以苹果添加了一个宏命令NS_SWIFT_NAME,允许在OC类在Swift环境下的重命名:

    NS_SWIFT_NAME(LoginManager)
    @interface XXLoginManager: NSObject
    @end
    复制代码
    

    这样我们就将XXLoginManager在Swift环境下的类名改为了LoginManager

    引用类型和值类型

    • struct 和 enum 是值类型,类 class 是引用类型。
    • StringArray和 Dictionary都是结构体,因此赋值直接是拷贝,而NSStringNSArrayNSDictionary则是类,所以是使用引用的方式。
    • struct 比 class 更“轻量级”,struct 分配在栈中,class 分配在堆中。

    id类型和AnyObject

    OC中id类型被Swift调用时会自动转成AnyObject,他们很相似,但却其实概念并不一致。Swift中还有一个概念是Any,他们三者的区别是:

    • id 是一种通用的对象类型,它可以指向属于任何类的对象,在OC中即是可以代表所有继承于NSObject的对象。
    • AnyObject可以代表任何class类型的实例。
    • Any可以代表任何类型,甚至包括func类型。

    从范围大小比较就是:id < AnyObject < Any

    其他语法区别及注意事项(待补充)

    1、Swift语句中不需要加分号;

    2、关于Bool类型更加严格,Swift不再是OC中的非0就是真,真假只对应truefalse

    3、Swift类内一般不需要写self,但是闭包内是需要写的。

    4、Swift是强类型语言,必须要指定明确的类型。在Swift中IntFloat是不能直接做运算的,必须要将他们转成同一类型才可以运算。

    5、Swift抛弃了传统的++--运算,抛弃了传统的C语言式的for循环写法,而改为for-in

    6、Swift的switch操作,不需要在每个case语句结束的时候都添加break

    7、Swift对enum的使用做了很大的扩展,可以支持任意类型,而OC枚举仅支持Int类型,如果要写兼容代码,要选择Int型枚举。

    8、Swift代码要想被OC调用,需要在属性和方法名前面加上@objc

    9、Swift独有的特性,如泛型,struct,非Int型的enum等被包含才函数参数中,即使添加@objc也不会被编译器通过。

    10、Swift支持重载,OC不支持。

    11、带默认值的Swift函数再被OC调用时会自动展开。

    语法检查

    对于OC转Swift之后的语法变化还有很多细节值得注意,特别是对于初次使用Swift这门语言的同学,很容易遗漏或者待着OC的思想去写代码。这里推荐一个语法检查的框架SwiftLint,可以自动化的检查我们的代码是否符合Swift规范。

    可以通过cocoapods进行引入,配置好之后,每次Build的过程,Lint脚本都会执行一遍Swift代码的语法检查操作,Lint还会将代码规范进行分级,严重的代码错误会直接报错,导致程序无法启动,不太严重的会显示代码警告(⚠️)。

    如果你感觉SwiftLint有点过于严格了,还可以通过修改.swiftlint.yml文件,自定义属于自己的语法规范。

    文章来源:掘金 zhangferry

    展开全文
  • 项目转Swift指南

    2020-05-16 15:47:17
    OCSwift有一个大前提就是你要对Swift有一定的了解,熟悉Swift语法,最好是完整看过一遍官方的Language Guide。 转换的过程分自动化和手动转译,鉴于自动化工具的识别率不能让人满意,大部分情况都是需要手动转换的...

    运行环境:Xcode 11.1 Swift5.0

    最近参与的一个项目需要从Objective-C(以下简称OC)转到Swift,期间遇到了一些坑,于是有了这篇总结性的文档。如果你也有将OC项目Swift化的需求,可以作为参考。

    OC转Swift有一个大前提就是你要对Swift有一定的了解,熟悉Swift语法,最好是完整看过一遍官方的Language Guide

    转换的过程分自动化和手动转译,鉴于自动化工具的识别率不能让人满意,大部分情况都是需要手动转换的。

    自动化工具

    有一个比较好的自动化工具Swiftify,可以将OC文件甚至OC工程整个转成Swift,号称准确率能达到90%。我试用了一些免费版中的功能,但感觉效果并不理想,因为没有使用过付费版,所以也不好评价它就是不好。

    Swiftify还有一个Xcode的插件Swiftify for Xcode,可以实现对选中代码和单文件的转化。这个插件还挺不错,对纯系统代码转化还算精确,但部分代码还存在一些识别问题,需要手动再修改。

    手动Swift化

    桥接文件

    如果你是在项目中首次使用Swift代码,在添加Swift文件时,Xcode会提示你添加一个.h的桥接文件。如果不小心点了不添加还可以手动导入,就是自己手动生成一个.h文件,然后在Build Settings > Swift Compiler - General > Objective-C Bridging Header中填入该.h文件的路径。

    这个桥接文件的作用就是供Swift代码引用OC代码,或者OC的三方库。

    #import "Utility.h"
    #import <Masonry/Masonry.h>
    

    Bridging Header的下面还有一个配置项是Objective-C Generated Interface Header Name,对应的值是ProjectName-Swift.h。这是由Xcode自动生成的一个隐藏头文件,每次Build的过程会将Swift代码中声明为外接调用的部分转成OC代码,OC部分的文件会类似pch一样全局引用这个头文件。因为是Build过程中生成的,所以只有.m文件中可以直接引用,对于在.h文件中的引用下文有介绍。

    Appdelegate(程序入口)

    Swift中没有main.m文件,取而代之的是@UIApplicationMain命令,该命令等效于原有的执行main.m。所以我们可以把main.m文件进行移除。

    系统API

    对于UIKit框架中的大部分代码转换可以直接查看系统API文档进行转换,这里就不过多介绍。

    property(属性)

    Swift没有property,也没有copynonatomic等属性修饰词,只有表示属性是否可变的letvar

    注意点一 OC中一个类分.h.m两个文件,分别表示用于暴露给外接的方法,变量和仅供内部使用的方法变量。迁移到Swift时,应该将.m中的property标为private,即外接无法直接访问,对于.h中的property不做处理,取默认的internal,即同模块可访问。

    对于函数的迁移也是相同的。

    注意点二 有一种特殊情况是在OC项目中,某些属性在内部(.m)可变,外部(.h)只读。这种情况可以这么处理:

    private(set) var value: String
    

    就是只对valueset方法就行private标记。

    注意点三 Swift中针对空类型有个专门的符号?,对应OC中的nil。OC中没有这个符号,但是可以通过在nullablenonnull表示该种属性,方法参数或者返回值是否可以空。

    如果OC中没有声明一个属性是否可以为空,那就去默认值nonnull

    如果我们想让一个类的所有属性,函数返回值都是nonnull,除了手动一个个添加之外还有一个宏命令。

    NS_ASSUME_NONNULL_BEGIN
    /* code */
    NS_ASSUME_NONNULL_END
    

    enum(枚举)

    OC代码:

    typedef NS_ENUM(NSInteger, PlayerState) {
        PlayerStateNone = 0,
        PlayerStatePlaying,
        PlayerStatePause,
        PlayerStateBuffer,
        PlayerStateFailed,
    };
    
    typedef NS_OPTIONS(NSUInteger, XXViewAnimationOptions) {
        XXViewAnimationOptionNone            = 1 <<  0,
        XXViewAnimationOptionSelcted1      	 = 1 <<  1,
        XXViewAnimationOptionSelcted2      	 = 1 <<  2,
    }
    

    Swift代码

    enum PlayerState: Int {
        case none = 0
        case playing
        case pause
        case buffer
        case failed
    }
    struct ViewAnimationOptions: OptionSet {
        let rawValue: UInt
        static let None = ViewAnimationOptions(rawValue: 1<<0)
        static let Selected1 = ViewAnimationOptions(rawValue: 1<<0)
        static let Selected2 = ViewAnimationOptions(rawValue: 1 << 2)
        //...
    }
    

    Swift没有NS_OPTIONS的概念,取而代之的是为了满足OptionSet协议的struct类型。

    懒加载

    OC代码:

    - (MTObject *)object {
        if (!_object) {
            _object = [MTObject new];
        }
        return _object;
    }
    

    Swift代码:

    lazy var object: MTObject = {
        let object = MTObject()
        return imagobjecteView
    }()
    

    闭包

    OC代码:

    typedef void (^DownloadStateBlock)(BOOL isComplete);
    

    Swift代码:

    typealias DownloadStateBlock = ((_ isComplete: Bool) -> Void)
    

    单例

    OC代码:

    + (XXManager *)shareInstance {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instance = [[self alloc] init];
        });
        return instance;
    }
    

    Swift对单例的实现比较简单,有两种方式:

    第一种

    let shared = XXManager()// 声明在全局命名区(global namespace)
    Class XXManager { 
    }
    

    你可能会疑惑,为什么没有dispatch_once,如何保证多线程下创建的唯一性?其实是这样的,Swift中全局变量是懒加载,在AppDelegate中被初始化,之后所有的调用都会使用该实例。而且全局变量的初始化是默认使用dispatch_once的,这保证了全局变量的构造器(initializer)只会被调用一次,保证了shard原子性

    第二种

    Class XXManager {
    		static let shared = XXManager()
      	private override init() {
       		// do something 
        }
    }
    

    Swift 2 开始增加了static关键字,用于限定变量的作用域。如果不使用static,那么每一个shared都会对应一个实例。而使用static之后,shared成为全局变量,就成了跟上面第一种方式原理一致。可以注意到,由于构造器使用了 private 关键字,所以也保证了单例的原子性。

    初始化方法和析构函数

    对于初始化方法OC先调用父类的初始化方法,然后初始自己的成员变量。Swift先初始化自己的成员变量,然后在调用父类的初始化方法。

    OC代码:

    // 初始化方法
    @interface MainView : UIView
    @property (nonatomic, strong) NSString *title;
    - (instancetype)initWithFrame:(CGRect)frame title:(NSString *)title NS_DESIGNATED_INITIALIZER;
    @end
    
    @implementation MainView
    - (instancetype)initWithFrame:(CGRect)frame title:(NSString *)title {
        if (self = [super initWithFrame:frame]) {
            self.title = title;
        }
        return self;
    }
    @end
    // 析构函数
    - (void)dealloc {
        //dealloc
    }
    

    上面类在调用时

    Swift代码:

    class MainViewSwift: UIView {
        let title: String
        init(frame: CGRect, title: String) {
            self.title = title
            super.init(frame: frame)
        }
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    		deinit {
          //deinit
        }
    }
    

    函数调用

    OC代码:

    // 实例函数(共有方法)
    - (void)configModelWith:(XXModel *)model {}
    // 实例函数(私有方法)
    - (void)calculateProgress {}
    // 类函数
    + (void)configModelWith:(XXModel *)model {}
    
    // 实例函数(共有方法)
    func configModel(with model: XXModel) {}
    // 实例函数(私有方法)
    private func calculateProgress() {}
    // 类函数(不可以被子类重写)
    static func configModel(with model: XXModel) {}
    // 类函数(可以被子类重写)
    class func configModel(with model: XXModel) {}
    // 类函数(不可以被子类重写)
    class final func configModel(with model: XXModel) {}
    

    OC可以通过是否将方法声明在.h文件表明该方法是否为私有方法。Swift中没有了.h文件,对于方法的权限控制是通过权限关键词进行的,各关键词权限大小为: private < fileprivate < internal < public < open

    其中internal为默认权限,可以在同一module下访问。

    NSNotification(通知)

    OC代码:

    // add observer
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(method) name:@"NotificationName" object:nil];
    // post
    [NSNotificationCenter.defaultCenter postNotificationName:@"NotificationName" object:nil];
    

    Swift代码:

    // add observer
    NotificationCenter.default.addObserver(self, selector: #selector(method), name: NSNotification.Name(rawValue: "NotificationName"), object: nil)
    // post
    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "NotificationName"), object: self)
    

    可以注意到,Swift中通知中心NotificationCenter不带NS前缀,通知名由字符串变成了NSNotification.Name的结构体。

    改成结构体的目的就是为了便于管理字符串,原本的字符串类型变成了指定的NSNotification.Name类型。上面的Swift代码可以修改为:

    extension NSNotification.Name {
    	static let NotificationName = NSNotification.Name("NotificationName")
    }
    // add observer
    NotificationCenter.default.addObserver(self, selector: #selector(method), name: .NotificationName, object: nil)
    // post
    NotificationCenter.default.post(name: .NotificationName, object: self)
    

    protocol(协议/代理)

    OC代码:

    @protocol XXManagerDelegate <NSObject>
    - (void)downloadFileFailed:(NSError *)error;
    @optional
    - (void)downloadFileComplete;
    @end
    
    @interface XXManager: NSObject
    @property (nonatomic, weak) id<XXManagerDelegate> delegate;  
    @end
    

    Swift中对protocol的使用拓宽了许多,不光是class对象,structenum也都可以实现协议。需要注意的是structenum为指引用类型,不能使用weak修饰。只有指定当前代理只支持类对象,才能使用weak。将上面的代码转成对应的Swift代码,就是:

    @objc protocol XXManagerDelegate {
        func downloadFailFailed(error: Error)
        @objc optional func downloadFileComplete() // 可选协议的实现
    }
    class XXManager: NSObject {
    	weak var delegate: XXManagerDelegate?  
    }
    

    @objc是表明当前代码是针对NSObject对象,也就是class对象,就可以正常使用weak了。

    如果不是针对NSObject对象的delegate,仅仅是普通的class对象可以这样设置代理:

    protocol XXManagerDelegate: class {
        func downloadFailFailed(error: Error)
    }
    class XXManager {
    	weak var delegate: XXManagerDelegate?
    }
    

    值得注意的是,仅@objc标记的protocol可以使用@optional

    Swift和OC混编注意事项

    函数名的变化

    如果你在一个Swift类里定义了一个delegate方法:

    @objc protocol MarkButtonDelegate {
        func clickBtn(title: String)
    }
    

    如果你要在OC中实现这个协议,这时候方法名就变成了:

    - (void)clickBtnWithTitle:(NSString *)title {
    	// code
    }
    

    这主要是因为Swift有指定参数标签,OC却没有,所以在由Swift方法名生成OC方法名时编译器会自动加一些修饰词,已使函数作为一个句子可以"通顺"。

    在OC的头文件里调用Swift类

    如果要在OC的头文件里引用Swift类,因为Swift没有头文件,而为了让在头文件能够识别该Swift类,需要通过@class的方法引入。

    @class SwiftClass;
    
    @interface XXOCClass: NSObject
    @property (nonatomic, strong) SwiftClass *object;
    @end
    

    对OC类在Swift调用下重命名

    因为Swift对不同的module都有命名空间,所以Swift类都不需要添加前缀。如果有一个带前缀的OC公共组件,在Swift环境下调用时不得不指定前缀是一件很不优雅的事情,所以苹果添加了一个宏命令NS_SWIFT_NAME,允许在OC类在Swift环境下的重命名:

    NS_SWIFT_NAME(LoginManager)
    @interface XXLoginManager: NSObject
    @end
    

    这样我们就将XXLoginManager在Swift环境下的类名改为了LoginManager

    引用类型和值类型

    • structenum 是值类型,类 class 是引用类型。
    • StringArrayDictionary都是结构体,因此赋值直接是拷贝,而NSString, NSArrayNSDictionary则是类,所以是使用引用的方式。
    • structclass 更“轻量级”,struct 分配在栈中,class 分配在堆中。

    id类型和AnyObject

    OC中id类型被Swift调用时会自动转成AnyObject,他们很相似,但却其实概念并不一致。Swift中还有一个概念是Any,他们三者的区别是:

    • id 是一种通用的对象类型,它可以指向属于任何类的对象,在OC中即是可以代表所有继承于NSObject的对象。
    • AnyObject可以代表任何class类型的实例。
    • Any可以代表任何类型,甚至包括func类型。

    从范围大小比较就是:id < AnyObject < Any

    其他语法区别及注意事项(待补充)

    1、Swift语句中不需要加分号;

    2、关于Bool类型更加严格,Swift不再是OC中的非0就是真,真假只对应truefalse

    3、Swift类内一般不需要写self,但是闭包内是需要写的。

    4、Swift是强类型语言,必须要指定明确的类型。在Swift中IntFloat是不能直接做运算的,必须要将他们转成同一类型才可以运算。

    5、Swift抛弃了传统的++--运算,抛弃了传统的C语言式的for循环写法,而改为for-in

    6、Swift的switch操作,不需要在每个case语句结束的时候都添加break

    7、Swift对enum的使用做了很大的扩展,可以支持任意类型,而OC枚举仅支持Int类型,如果要写兼容代码,要选择Int型枚举。

    8、Swift代码要想被OC调用,需要在属性和方法名前面加上@objc

    9、Swift独有的特性,如泛型,struct,非Int型的enum等被包含才函数参数中,即使添加@objc也不会被编译器通过。

    10、Swift支持重载,OC不支持。

    11、带默认值的Swift函数再被OC调用时会自动展开。

    语法检查

    对于OC转Swift之后的语法变化还有很多细节值得注意,特别是对于初次使用Swift这门语言的同学,很容易遗漏或者待着OC的思想去写代码。这里推荐一个语法检查的框架SwiftLint,可以自动化的检查我们的代码是否符合Swift规范。

    可以通过cocoapods进行引入,配置好之后,每次Build的过程,Lint脚本都会执行一遍Swift代码的语法检查操作,Lint还会将代码规范进行分级,严重的代码错误会直接报错,导致程序无法启动,不太严重的会显示代码警告(⚠️)。

    如果你感觉SwiftLint有点过于严格了,还可以通过修改.swiftlint.yml文件,自定义属于自己的语法规范。

    推荐👇:

    • 020 持续更新,精品小圈子每日都有新内容,干货浓度极高。

    • 结实人脉、讨论技术 你想要的这里都有!

    • 抢先入群,跑赢同龄人!(入群无需任何费用)

    • (直接搜索群号:789143298,快速入群)
    • 点击此处,与iOS开发大牛一起交流学习

    申请即送:

    • BAT大厂面试题、独家面试工具包,

    • 资料免费领取,包括 数据结构、底层进阶、图形视觉、音视频、架构设计、逆向安防、RxSwift、flutter,

    作者:zhangferry
    链接:https://juejin.im/post/5e5a4f20518825495a277aa7

    展开全文
  • 下边是作者的框架的下载地址 ,基于swift2.0 https://github.com/danielgindi/ios-charts.git 只需要把demo中的chart 下的文件classf xcode中做如下设置 在使用框架的界面导入一下的头文件‘ #import ...
  • 资料1 ---教程类 官方文档中文翻译http://wiki.jikexueyuan.com/project/swift/Github上的地址点我 Using Swift with Cocoa and Objective-C ...Swift 开源及跨平台开发swift.org 斯坦福课程Stanford Un
  • Swift、Xcode和Cocoa入门指南(iOS9 Programming Fundamentals With swift) 第四章 对象类型  第三章介绍了一些内建对象类型,不过还没有谈及对象类型本身(即 枚举 结构体 和 类);    本章结构: ...
  • 1、柯里化 把接受多个参数的方法进行一些变形,使其更加灵活的方法。函数式特点的重要表现。 举个例子,下面的函数简单地将输入的数字加 1: func addOne(num: Int) ->...这个函数所表达的内容非常有限,如果...
  • 在iOS8和OSX10.10中SpriteKit迎来了重大升级。在物理表现方面增加了着色器,光照和阴影;在物理模拟方面增加了像素物理体、力场和宇宙动力学和约束等;在Xcode中集成了场景编辑器,你不需要写代码就能完成一些复杂的...
  • Swift笔记一

    2020-05-16 01:21:54
    Swift 高级 一.基础概述 1.基础的基础 值(value):不变的,永久的,可以是人为定义的,也可以是运行时候生成的。 变量:可以被刷新更改的,用var定义,更新的过程称为变量的改变(mutating)。 常量变量:用let...
  • 下拉刷新 EGOTableViewPullRefresh - 最早的下拉刷新控件。SVPullToRefresh - 下拉刷新控件。MJRefresh - 仅需一行代码就可以为UITableView或者CollectionView加上下拉刷新或者上拉刷新功能。...
  • 酷课堂iOS交流群   我们是一个什么样的组织: 酷课堂iOS交流群,聚集了一群热爱技术、有趣、有料,平均Q龄在10年以上的“老司机”,他们遍布在全国/球各地,有知名企业iOS工程师、高校大学生、自由职业者……...
  • 下拉刷新 EGOTableViewPullRefresh - 最早的下拉刷新控件。SVPullToRefresh - 下拉刷新控件。MJRefresh - 仅需一行代码就可以为UITableView或者CollectionView加上下拉刷新或者上拉刷新功能
  • React Native 调研报告

    2015-04-28 09:28:55
    让移动开发人员和web开发者都各自兴奋了一把:native的移动开发者想的比较多的估计是Facebook的那句:“learn once, write everywhere”,而web开发者兴奋的估计是,不需要学习iOS那陌生的OC或者swift语言,用自己...
  • 转自: http://www.cnblogs.com/zyjzyj/p/6015625.html github排名:https://github.com/trending, github搜索:https://github.com/search. 此文章转自github:...
  • iOS非常全的第三方库

    2017-06-14 16:34:28
    转载: http://www.cnblogs.com/zyjzyj/p/6015625.html iOS ● 非常全的三方库、插件、大牛博客等等   github排名:https://github.com/trending, github搜索:https://github.com/search....
  • 下拉刷新 EGOTableViewPullRefresh - 最早的下拉刷新控件。SVPullToRefresh - 下拉刷新控件。MJRefresh - 仅需一行代码就可以为UITableView或者CollectionView加上下拉刷新或者上拉刷新功能。...
  • 目录UI下拉刷新模糊效果AutoLayout富文本图表表相关与Tabbar隐藏与显示HUD与Toast对话框其他UI动画侧滑与右滑返回手势gif动画其他动画网络相关网络连接图像获取网络聊天网络测试网页框架WebView与WKWebViewModel...
1 2 3 4 5 ... 8
收藏数 141
精华内容 56
关键字:

oc swift 精确桥接