oc 调用swift扩展类_oc 调用 swift 扩展类 - CSDN
  • iOS OC项目调用Swift类

    2017-03-17 13:51:27
    网上有很多关于OC项目中使用Swift类的方法,但是亲自试了之后,发现不够详细,多次尝试后,终于找出详细的方法。 现把方法和遇到的问题,记录下来,方便其他同仁借鉴.

    网上有很多关于OC项目中使用Swift类的方法,但是亲自试了之后,发现不够详细,多次尝试后,终于找出详细的方法。
    现把方法和遇到的问题,记录下来,方便其他同仁借鉴:

    一、新建一个OC工程,工程名称自定,在这里我定义为OCAndSwiftDemo,如图:

    新建项目架构图

    二、在新建Swift类之前,进行相关设置,如图:

    相关设置

    三、在项目中,新建一个TestDemo的swift类,点击Create后,提示如图:

    创建OC调用Swift类的桥接文件

    选择Create Bridging Header,一定要选择这个,如果不选择,就引入不了Swift类,然后生成”项目名称-Bridging-Header.h”桥接文件

    然后编辑Swift类,如果Swift类想要被OC发现,必须继承自NSObject,如图:

    TestDemo类

    四、调用Swift类,我们想要调用Swift类的方法里面引入头文件:”项目名称-Swift.h”,如图:

    调用Swift类

    注释:如果调用不了Swift类,可以先Shift+Command+R一下。

    展开全文
  • 版权声明:本文为博主原创文章,未经博主允许不得转载。 目录(?...最新一些学妹问起,所以抽点时间来写的,适合入门...1. 第一个方向从 swift工程 中引入 oc类   1. 1 如何在swift中使用oc类  1.2 如何在s
    
    

    目录(?)[+]

    最新一些学妹问起,所以抽点时间来写的,适合入门级别的swift 与 OC 混编 的程序猿。  

    本文章将从两个方向分别介绍 OC 与 swift 混编  


    1. 第一个方向从 swift工程 中引入 oc类 

        1. 1 如何在swift的类中使用oc类
        1.2  如何在swift中实现oc的代理方法
        1.3   如何在swift中实现oc的Block回调

    2. 第二个方向从OC工程中引入swift类

        2.1  如何在OC类中使用swift类
        2.2   如何在OC中实现swift的代理方法
        2.3   如何在OC中实现swift中类似Block回调


    下面是具体的实现过程:

     1.1  如何在swift的类中使用oc类? 

    1.  Swift工程中引入OC类。 具体实现过程。

        1.1 新建一个swift工程类。 取名 swiftOrOC

        1.2  实现的功能为 :  从swift. viewController.swift 中 push到 OC语言 secondViewController 控制器

    1.2.1  新建SecondViewController 类 。

            

         1.2.2 建立桥接文件。 (很重要)


        一定要记得点击这个按钮。 

           1.2.3  接下来工程目录如下:

           

         1.2.4 接下来就可以实现具体的跳转功能了。 

          ViewController.swift中具体实现

         

    [objc] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. import UIKit  
    2.   
    3. class ViewController: UIViewController {  
    4.   
    5.     @IBOutlet weak var hintLabel: UILabel!  //稍后用来显示回调  
    6.       
    7.     // push 到 oc controller  
    8.     @IBAction func pushAction(_ sender: AnyObject) {  
    9.         let secondVC = SecondViewController.init()  
    10.         self.navigationController?.pushViewController(secondVC, animatedtrue)  
    11.     }  
    12.       
    13.     override func viewDidLoad() {  
    14.         super.viewDidLoad()  
    15.         // Do any additional setup after loading the view, typically from a nib.  
    16.     }  
    17.   
    18.     override func didReceiveMemoryWarning() {  
    19.         super.didReceiveMemoryWarning()  
    20.         // Dispose of any resources that can be recreated.  
    21.     }  
    22.   
    23.   
    24. }  


    1.2 如何在swift中实现oc的代理方法

           1.2.1 首先在 SecondViewController.h 中声明一个协议。具体代码

            

    [objc] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #import <UIKit/UIKit.h>  
    2.   
    3. @protocol SecondDelegate <NSObject>  
    4.   
    5. -(void)refreshHintLabel:(NSString *)hintString;  
    6.   
    7. @end  
    8.   
    9. @interface SecondViewController : UIViewController  
    10.   
    11. @property (nonatomic,weak)id<SecondDelegate> secondDelegate;  
    12. @end  
         1.2.2 然后在SecondViewController.m中,通过一个UITextField,让用户输入内容,当用户点击返回的时候把输入框中的内容返回给对应的代理。具体代码如下

        

    [objc] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #import "SecondViewController.h"  
    2. #import "UIViewController+BackButtonHandler.h"  
    3.   
    4. @interface SecondViewController ()  
    5. {  
    6.     UITextField *textField;  
    7. }  
    8. @end  
    9.   
    10. @implementation SecondViewController  
    11.   
    12. - (void)viewDidLoad {  
    13.     [super viewDidLoad];  
    14.     self.title = @"oc";  
    15.       
    16.     self.view.backgroundColor  = [UIColor whiteColor];  
    17.       
    18.     textField = [[UITextField alloc]initWithFrame:CGRectMake(100100200200)];  
    19.     textField.placeholder = @"请输入用户名";  
    20.     [self.view addSubview:textField];  
    21.     [textField.layer setBorderColor:[UIColor blackColor].CGColor];  
    22.     [textField.layer setBorderWidth:1.0];  
    23.   
    24.       
    25. }  
    26.   
    27. -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{  
    28.     [self.view endEditing:YES];  
    29. }  
    30. #pragma mark 返回上一页回调 ,将用户输入的用户名传回给 ViewController.swift  
    31. -(BOOL)navigationShouldPopOnBackButton{  
    32.     if ([_secondDelegate respondsToSelector:@selector(refreshHintLabel:)]) {  
    33.         [_secondDelegate refreshHintLabel: textField.text];  
    34.     }  
    35.       
    36.     return YES;  
    37. }  
    38.   
    39.   
    40. - (void)didReceiveMemoryWarning {  
    41.     [super didReceiveMemoryWarning];  
    42.     // Dispose of any resources that can be recreated.  
    43. }  
    44.   
    45. /* 
    46. #pragma mark - Navigation 
    47.  
    48. // In a storyboard-based application, you will often want to do a little preparation before navigation 
    49. - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 
    50.     // Get the new view controller using [segue destinationViewController]. 
    51.     // Pass the selected object to the new view controller. 
    52. } 
    53. */  
    54.   
    55. @end  
      1.2.3 接下来就非常简单了,让ViewController.swift只需要成为SecondViewController的代理,然后遵循她的协议,就可以了。 具体代码如下。

           1.2.3.1 遵循协议

      

         1.2.3.2 成为代理,并实现协议方法,更改controller.swift中hintLabel的text。

    [objc] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. // push 到 oc controller  
    2. @IBAction func pushAction(_ sender: AnyObject) {  
    3.     let secondVC = SecondViewController.init()  
    4.     secondVC.secondDelegate = self;  
    5.     self.navigationController?.pushViewController(secondVC, animatedtrue)  
    6. }  
    7.   
    8. // SecondViewControll的代理方法  
    9. func refreshHintLabel(_ hintString: String!) {  
    10.     hintLabel.text = "secondView textView.text = " + hintString;  
    11. }  

     1.3   如何在swift中实现oc的Block回调

    1.3.1 具体过程与1.2小节一样。 直接上代码。

            1.3.2 声明block;

             

    [objc] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. typedef void(^RefreshHintLabelBlock)(NSString *hintString);  
    2.   
    3. @interface SecondViewController : UIViewController  
    4. @property (nonatomiccopy) RefreshHintLabelBlock hintBlock;  
    5. @end  

            1.3.3 block的回调。 SecondViewController.m中

    [objc] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #pragma mark 返回上一页回调 ,将用户输入的用户名传回给 ViewController.swift  
    2. -(BOOL)navigationShouldPopOnBackButton{      
    3.     if (_hintBlock) {  
    4.         _hintBlock(textField.text);  
    5.     }  
    6.     return YES;  
    7. }  

            1.3.4 在swift类中调用 oc的block.

    [objc] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. // push 到 oc controller  
    2. @IBAction func pushAction(_ sender: AnyObject) {  
    3.     let secondVC = SecondViewController.init()  
    4.       secondVC.secondDelegate = self;  
    5.     secondVC.hintBlock = {(t:String?)in  
    6.         self.hintLabel.text = "secondView textView.text = " + t!  
    7.     }  
    8.     self.navigationController?.pushViewController(secondVC, animatedtrue)  
    9. }  


       工程已上传到Git上,git地址: https://github.com/zhonggaorong/SwiftOrOc/tree/master

    2.  OC工程中引入swift类。 具体实现过程。

        耽误了不少时间, 今天才开始写oc工程中引入swift类。

        demo地址: 

      

         2.1  如何在OC类中使用swift类


           2.1.1   新建一个基于OC语言的工程 ,取名 OcOrSwiftTwo
           2.1. 2  实现的功能为 : 从oc类 viewcontroller中, push 至 swift语言 SecondViewController  ,然后SecondViewController可以通过代理或者swift闭包把值传回viewcontroller. 
           2.1.3   当前文件目录看下图:  (第四个箭头: 桥接文件)
            
      
        2.2   如何在OC中实现swift的代理与闭包Block方法
                
        2.2.1 如何在oc中引入swift类。#import "工程名-swift.h"
    [objc] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #import "OcOrSwiftTwo-swift.h"  
       2.2.2 在secondViewController.swift 中实现代理与闭包,代码如下:
        注意: @objc(代理名)  才能在外部可见这个代理
     
    [objc] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. import UIKit  
    2. import Foundation  
    3.   
    4. // 必须加上@objc 代理才能在oc类中可见。  
    5. @objc(EditTextFieldDelegate)  
    6. protocol EditTextFieldDelegate:NSObjectProtocol {  
    7.     func editTextField(_ str: String) -> Void  
    8. }  
    9.   
    10. @objc(SecondViewController)  
    11. class SecondViewController: UIViewController {  
    12.   
    13.     var editorDelegate:EditTextFieldDelegate?  
    14.     var textField:UITextField?  
    15.     var addButton:UIButton?  
    16.     var pushButton:UIButton?  
    17.       
    18.     typealias editorBlock = (_ t:String) -> Void  
    19.     var myEidtorBlock:editorBlock?  
    20.       
    21.     override func viewDidLoad() {  
    22.         super.viewDidLoad()  
    23.         self.view.backgroundColor = UIColor.white  
    24.         textField = UITextField.init(frame: CGRect.init(x: 50, y60, width200, height50))  
    25.         textField?.placeholder = "输入返回首页的内容"  
    26.         self.view.addSubview(textField!)  
    27.           
    28.         addButton = UIButton.init(type: .custom)  
    29.         addButton?.setTitleColor(UIColor.black, for.normal)  
    30.         addButton?.setTitle("pop", for.normal)  
    31.         addButton?.frame = CGRect.init(x: 50, y150, width200, height50)  
    32.         addButton?.layer.borderColor = UIColor.black.cgColor  
    33.         addButton?.layer.borderWidth = 1.0  
    34.         addButton?.addTarget(self, action: #selector(popAction), for.touchUpInside)  
    35.         self.view.addSubview(addButton!)  
    36.           
    37.           
    38.           
    39.         pushButton = UIButton.init(type: .custom)  
    40.         pushButton?.setTitleColor(UIColor.black, for.normal)  
    41.         pushButton?.setTitle("push", for.normal)  
    42.         pushButton?.frame = CGRect.init(x: 50, y250, width200, height50)  
    43.         pushButton?.layer.borderColor = UIColor.black.cgColor  
    44.         pushButton?.layer.borderWidth = 1.0  
    45.         pushButton?.addTarget(self, action: #selector(pushAction), for.touchUpInside)  
    46.         self.view.addSubview(pushButton!)  
    47.           
    48.     }  
    49.       
    50.     func popAction() -> Void {  
    51.           
    52.         if editorDelegate != nil {  
    53.             editorDelegate?.editTextField((textField?.text)!)  
    54.         }  
    55.           
    56.         if ((self.myEidtorBlock) != nil){  
    57.             self.myEidtorBlock!((textField?.text!)!)  
    58.         }  
    59.           
    60.         self.navigationController?.popViewController(animated: true)  
    61.     }  
    62.       
    63.       
    64.     func pushAction() -> Void {  
    65.         let three = ThreeViewController.init()  
    66.         self.navigationController?.pushViewController(three, animatedtrue)  
    67.           
    68.     }       
        2.2.3   在oc类中viewcontroller.m 文件中实现SecondviewController.swift的相关代理与闭包(block). 代码如下:
       
    [objc] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #import "ViewController.h"  
    2. #import "OcOrSwiftTwo-swift.h"  
    3.   
    4. @interface ViewController ()<EditTextFieldDelegate>  
    5. @property (nonatomicstrongUITextField *showTextField;  
    6. @property (nonatomicstrongUIButton *pushButton;  
    7.   
    8. @end  
    9.   
    10. @implementation ViewController  
    11.   
    12. - (void)viewDidLoad {  
    13.     [super viewDidLoad];  
    14.     _showTextField = [[UITextField alloc]initWithFrame:CGRectMake(50100 , 20050)];  
    15.     _showTextField.placeholder = @"swift传回的文本内容";  
    16.     _showTextField.adjustsFontSizeToFitWidth = YES;  
    17.     _showTextField.enabled = NO;  
    18.     [self.view addSubview:_showTextField];  
    19.       
    20.     _pushButton = [UIButton buttonWithType:UIButtonTypeCustom];  
    21.     [_pushButton.layer setBorderColor:[UIColor blackColor].CGColor];  
    22.     [_pushButton.layer setBorderWidth:1.0];  
    23.     [_pushButton setFrame:CGRectMake(5020020050)];  
    24.     [_pushButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];  
    25.     [_pushButton setTitle:@"push" forState:UIControlStateNormal];  
    26.     [_pushButton addTarget:self action:@selector(pushAction) forControlEvents:UIControlEventTouchUpInside];  
    27.       
    28.     [self.view addSubview:_pushButton];  
    29. }  
    30.   
    31.   
    32.   
    33.   
    34. -(void)pushAction{  
    35.     SecondViewController *second = [[SecondViewController alloc]init];  
    36.     // second.editorDelegate = self;  
    37.       
    38.     /* 
    39.       swift中的闭包回滴 
    40.      */  
    41.     second.myEidtorBlock = ^(NSString *str) {  
    42.         _showTextField.text = [NSString stringWithFormat:@"second传回信息: %@",str];  
    43.     };  
    44.     [self.navigationController pushViewController:second animated:YES];  
    45. }  
    46.   
    47. #pragma mark swift中的代理  
    48. -(void)editTextField:(NSString *)str{  
    49.     _showTextField.text = [NSString stringWithFormat:@"second传回信息: %@",str];  
    50. }  
    51.   
    52. - (void)didReceiveMemoryWarning {  
    53.     [super didReceiveMemoryWarning];  
    54.     // Dispose of any resources that can be recreated.  
    55. }  

    展开全文
  • 概述 Swift的设计的初衷就是摆脱...随着Swift的改进及Swift开源项目剧增,越来越多的Objective-C工程开始使用Swift混编,不管是在基于Swift工程中或者Objective-C工程中,Swift和Objective-C文件都可以无缝结合。本文

    概述

    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中有效的接口。

    展开全文
  • OC/swift /结构体

    2019-10-23 13:21:26
    ----------- OC --------- 1.结构体与的相同点: a.都可以将多个数据封装为1个整体。 1.不同点 a.结构体只能封装数据,而还可以封装行为 b.结构体变量分配在栈空间(如果是是1个局部变量的情况下)...

    ----------- OC ---------

     

    1. 结构体与类的相同点:

    a. 都可以将多个数据封装为1个整体。

     

    1.    不同点

     

    a.    结构体只能封装数据,而类还可以封装行为

     

    b.    结构体变量分配在栈空间(如果是是1个局部变量的情况下),而对象分配在堆空间。

     

                                i.        栈的特点:空间相对较小,但是存储在栈中得数据访问的效率稍高一些

     

                              ii.        堆的特点:空间的相对较大,但是存储在堆中的数据,效率低一些

     

                             iii.        存储在栈中得数据访问效率高, 存储在堆中得数据效率低

     

    c. 赋值

     

                i.     结构体  (拷贝)

     

               ii.     对象之间 是(地址)

     

                  结构体 Student

     

           类:   Person

     iii.      

     

    2. 应用场景

     

    a. 如果封装的这个数据,不仅有数据还有方法,只能使用类

     

    b. 如果表示实体,没有行为,光有属性,

     

                i.     如果属性较少,只有几个的情况下,就定义为结构体,分配在栈,提高运行效率

     

               ii.     如果属性较多,就不要定义为结构体,因为这样结构体变量会在栈中占据很大一块空间,反而会影响效率

    ----- swift ----

     

    1.Swift不需要你为自定义类和结构体创建独立的接口和实现文件。在 Swift 中,你在一个文件中定义一个类或者结构体, 则系统将会自动生成面向其他代码的外部接口。
    2.类与结构体的对比:
    在 Swift 中类和结构体有很多共同之处,它们都能:

    • 定义属性用来存储值;
    • 定义方法用于提供功能;
    • 定义下标脚本用来允许使用下标语法访问值;
    • 定义初始化器用于初始化状态;
    • 可以被扩展来默认所没有的功能;
    • 遵循协议来针对特定类型提供标准功能。

    类有而结构体没有的额外功能:

    • 继承允许一个类继承另一个类的特征;
    • 类型转换允许你在运行检查和解释一个类实例的类型;
    • 反初始化器允许一个类实例释放任何其所被分配的资源;
    • 引用计数允许不止一个对类实例的引用。

    3.结构体在你的代码中通过复制来传递,并且并不会使用引用计数。

    4.定义:无论你在何时定义了一个新的类或者结构体,实际上你定义了一个全新的 Swift 类型。

    
     

    5.初始化器语法最简单的是在类或结构体名字后面接一个空的圆括号,例如 Resolution()或者 VideoMode()。

    6.结构体类型的成员初始化器

    
     

    7.结构体和枚举是值类型
    值类型是一种当它被指定到常量或者变量,或者被传递给函数时会被拷贝的类型。
    Swift 中所有的结构体和枚举都是值类型,这意味着你所创建的任何结构体和枚举实例——和实例作为属性所包含的任意值类型——在代码传递中总是被拷贝的。

    8.类是引用类型
    相对于拷贝,这里使用的是同一个对现存实例的引用。

    9.有时候找出两个常量或者变量是否引用自同一个类实例非常有用,为了允许这样,Swift提供了两个特点运算符:

    • 相同于 ( ===),意味着两个类类型常量或者变量引用自相同的实例;
    • 不相同于( !==)

    10.按照通用准则,当符合以下一条或多条情形时应考虑创建一个结构体:

    • 结构体的主要目的是为了封装一些相关的简单数据值;
    • 当你在赋予或者传递结构实例时,有理由需要封装的数据值被拷贝而不是引用;
    • 任何存储在结构体中的属性是值类型,也将被拷贝而不是被引用;
    • 结构体不需要从一个已存在类型继承属性或者行为。

    11.字符串,数组和字典的赋值与拷贝行为
    Swift 的 String , Array 和 Dictionary类型是作为结构体来实现的,这意味着字符串,数组和字典在它们被赋值到一个新的常量或者变量,亦或者它们本身被传递到一个函数或方法中的时候,其实是传递了拷贝。

    12.在上述有关字符串,数组和字典“拷贝”的描述中。你在代码中所见到的行为好像总是拷贝。然而在后台 Swift 只有在需要这么做时才会实际去拷贝。Swift 能够管理所有的值的拷贝来确保最佳的性能,所有你也没必要为了保证最佳性能来避免赋值。

    swift:文章转载地址

    https://www.jianshu.com/p/e5a8a3fd407d

     

    展开全文
  • 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开发 创建Extension(即OC中的category)
  • 接上篇文章:iOS 快速从OC过渡到Swift,由理论到实战-Swift基础 OCSwift混编 a. SwiftOC 的映射关系 Swift 兼容来大部分 OC,当然还有一些 Swift 不能够使用的,例如 OC 中的预处理指令,即宏定义不可...
  • 本文旨在帮助开发者快速从OC开发过渡到Swift开发,挑选了一些比较浅显的但是比较常用的Swift语法特性,在介绍的过程中,通常会拿OC中的语言特性作比较,让大家更好的注意到Swift的不同。 另外需要说明的是,笔者也...
  • 首先我发现在编写Swift代码的时候,经常会遇到Xcode不能提示,卡顿,直接闪退等问题,尤其是在SwiftOC混编时。(不知道其他开发者是否也有这样的经历,但是我相信这样的问题,很快会得到解决) 然后感觉Swift并...
  • Swift 扩展存储属性

    2019-08-27 20:41:46
    Swift扩展存储属性 Swift默认只能扩展计算属性无法扩展存储属性,如果想扩展存储属性就需要使用runtime。 使用runtime的两个核心方法(关联对象) /// 设置值 /// - 参数1: 为哪个对象设置 参数2: 属性的指针...
  • // // UIButtonExtension.swift // ZYFWB // // Created by fe on 2017/3/8. // Copyright © 2017年 fe. All rights reserved. // import UIKit ...//UIButton的方法扩展 ... //这里的方法相当于OC
  • 标签: Objective-Cios开发移动互联网扩展类 |2015-03-04 16:06 |2082人阅读 一、分类  1、适用范围  当你已经封装好了一个类(也可能是系统类、第三方库),不想在改动这个类了,可是随着程序功能的增加...
  • Swift协议&扩展
  • OC项目转Swift指南

    2020-07-11 15:07:53
    OCSwift有一个大前提就是你要对Swift有一定的了解,熟悉Swift语法,最好是完整看过一遍官方的Language Guide。 转换的过程分自动化和手动转译,鉴于自动化工具的识别率不能让人满意,大部分情况都是需要手动转换的...
  • swift不支持C++混编,也不能调用C++的或者函数,得用OC包一层。倒是可以调用C的函数,可能是C++的语法太复杂了。 如果是.m文件,可以用OC和C的代码; 如果是.mm文件,可以用OC和C和C++的代码;.m 和.mm 的区别是...
  • 看到我Swift代码的人会立即询问,为什么要使用这么多的扩展。下面是我另一篇文章下面的一条评论:翻译如下:非常感谢,这篇文章很不错。我一直疑惑你为什么要用这么多不必要的扩展,我认为你并未按照正确的用途来...
  • Swift学习这二十二:扩展(extension)
  • // MARK:类似于OC中的#pragma mark // MARK: -类似于OC中的#pragma mark - //TODO:用于标记未完成的任务 // FIXME:用于标记待修复的问题 #warning: 用于标记未完成的任务或需要提醒的任务 左边在代码中写的标记...
  • Swift相比OC语言有哪些优点 1、自动做类型推断 2、可以保证类型使用安全 Swif类型说明符 ——Swift增加了Tuple表示元组类型 ——Swift增加了Optional表示可选类型 常量一变量命名: ——可以用任何你喜欢的字符作为...
1 2 3 4 5 ... 20
收藏数 2,436
精华内容 974
关键字:

oc 调用swift扩展类