升级Swift4.0遇到的坑

DFU固件升级 蓝牙BLE4.0 最近研究DFU固件升级,由于网上的资源非常少,也走了很多弯路。经过一段时间的研究,写出了一个demo测试可用。可以使用2019最新的官方库。希望能够帮到大家。 进入正题,现在的DFU固件升级基本都是使用NRF的github开源库,公司和厂商也有合作,中国区只有代理,如果有技术问题可以发邮件给欧洲的厂商。但是经过最终确认厂商不提供技术支持,所以只能自己翻文档,看代码了。官方提供的资源如下 1&g... 阅读详情

升级Swift4.0

  • 并不是所有库都能做到及时支持Swift4.0,更何况是在现在连Xcode9也还是beta的状态
  • 所以我们仅能做到将自己的业务代码(主工程代码)部分升级到Swift4.0,然后同时保留各种pod库在Swift3.2版本。
  • 没办法,谁叫Swift4.0也还无法做到API兼容呢(但愿能在Swift5之前实现吧)。
  • 至于我说的同时使用两个版本的Swift,这是没问题的,Xcode9支持在项目中同时使用Swift3.2和Swift4.0。

一. 修改Swift版本

1. 如下图指定主工程的Swift版本为4.0
Xcode图示.png
Xcode图示.png
2. 修改pod库
  • 在Podfile文件的最下方加入如下代码,指定pod库的Swift版本为3.2(这样会使得所有的第三方pod库的Swift版本都为3.2)
post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['SWIFT_VERSION'] = '3.2'
    end 
  end
end

二. 主工程中的代码修改

1. 列举一下Swift3.2到Swift4.0的改变(只是我项目中遇到的):

  • 1). Swift4.0中对于扩展的属性(包括实例属性、static属性、class属性),都只能使用get方法,不可使用set方法

  • 2). Swift4.0中不再允许复写扩展中的方法(包括实例方法、static方法、class方法)

    • 比如:自定义的协议方法在extension中实现,若某个类遵循了该协议,其子类便不能重写该协议方法
    • 解决的方法是: 在每个需要该协议的类里面都重新遵循该协议,实现协议方法
    • 个人想到的办法,不知道有没有其他解决办法可以提供一下
  • 3). swift3使用#selector指定的方法,只有当方法权限为private时需要加@objc修饰符,现在Swift4.0全都要加@objc修饰符

  • 4). 自定义的protocol协议中,有optional修饰的非必须实现的方法,需要用@objc修饰

  • 5). 字体方面的一些重命名

NSFontAttributeName --- .font 
//或者NSAttributedStringKey.font

NSForegroundColorAttributeName --- .foregroundColor
//NSAttributedStringKey.foregroundColor

NSStrikethroughStyleAttributeName --- .strikethroughStyle
//NSAttributedStringKey.strikethroughStyle

//字符串类型的,添加rawValue
NSAttributedStringKey.font.rawValue

//等等等等..........

//大部分类似以下,涉及富文本的方法均已改为了NSAttributedStringKey类型
addAttributes(_ attrs: [NSAttributedStringKey : Any] = [:], range: NSRange)

三. 项目中遇到的一些的报错问题

3-1. "Closure cannot implicitly capture a mutating self parameter"错误

在struct中,如果我们在闭包中使用self,就会得到Closure cannot implicitly capture a mutating self parameter的错误提示。比如:


struct RecordModel {
    /// 定义一个闭包
    var action: (() -> ())?
    var height = 10
    
    self.action = { 
        self.height = 20 
        //Closure cannot implicitly capture a mutating self parameter报错
    }
}
++并且由于RecordModel的类型是struct,我们也没发在action闭包里添加截获列表。那么是不是就必须使用class了?答案是否定的。有两种方式可以解决这个问题。++
方案一:为closure增加一个inout类型的参数

struct RecordModel {
    /// 定义一个闭包
    var action: ((_ inSelf: inout RecordModel) -> ())?
    var height = 10
    
    self.action = { (inSelf) in
        inSelf.height = 20 
    }
}

根据inout类型的说明,我们知道,实际上这相当于增加了一个隐藏的临时变量,self被复制,然后在closure(闭包)中使用,完成后,再复制回self。也就是说,这个方法有额外的内存开销。如果是struct较大的情形,这么做并不划算。
方案二:使用UnsafeMutablePointer<Pointee>
  • ==这次采用直接指针的方式对于struct来进行操作,采用指针的好处是self不会被多次复制,性能较高。缺点是你需要自行确定你的代码的安全。==

struct RecordModel {
    /// 定义一个闭包
    var action: (() -> ())?
    var height = 10
    
    let selfPointer = UnsafeMutablePointer(&self)
    self.action = { 
        selfPointer.pointee.height = 20 
        
    }
}

结论

==Closure cannot implicitly capture a mutating self parameter错误的原因是在进出closure(闭包)之后,self的一致性没办法得到保证,所以编译器默认不允许在struct的closure(闭包)中使用self。如果我们确定这么做是安全的,就可以通过上面的两种方式解决这个问题。其中,方法二的性能更好一些。==

注意
这里可以记一下指针和swift变量之间的关系:
  • UnsafePointer对应let
  • UnsafeMutablePointer对应var
  • AutoreleasingUnsafeMutablePointer对应unowned UnsafeMutablePointer,用于inout的参数类型
  • UnsafeRawPointer对应let Any,raw系列都是对应相应的Any类型
  • UnsafeBufferPointer是non-owning的类型(unowned),用于collection的elements, buffer系列均如此

3-2. Declarations from extensions cannot be overridden yet 错误

==这个错误大致是因为,协议方法是在extension里面的,不能被重写==

解决办法:(仅供参考,如有更好的建议还望多多指教)

  • 小编想到的解决办法就是在每一个需要此协议的类里面,重新遵循代理,实现该协议方法

3-3. "Method 'initialize()' defines Objective-C class method 'initialize', which is not permitted by Swift"

==报错原因: 在于已经废弃的initialize方法,示例如下==

  • 方法交叉(Method Swizzling)
    • 有时为了方便,也有可能是解决某些框架内的 bug,或者别无他法时,需要修改一个已经存在类的方法的行为。方法交叉可以让你交换两个方法的实现,相当于是用你写的方法来重载原有方法,并且还能够是原有方法的行为保持不变。
extension UIViewController {
    public override class func initialize() {//此处报错
        
    //此处省略100行代码
        
    }
}

  • initialize该方法已经被Swift4.0废弃
  • 在Swift3.0还勉强可以使用,但是会有警告;但是在4.0已经被完全废弃

==替代方法:==

  • 在 app delegate 中实现方法交叉
  • 像上面通过类扩展进行方法交叉,而是简单地在 app delegate 的 application(_:didFinishLaunchingWithOptions:) 方法调用时调用该方法
extension UIViewController {
    public override class func initializeOnceMethod() {
        
    //此处省略100行代码
        
    }
}

//在AppDelegate的方法中调用:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
    //此处省略100行代码
    UIViewController.initializeOnceMethod()

}

3-4. 'dispatch_once' is unavailable in Swift: Use lazily initialized globals instead

报错原因: dispatch_once在Swift4.0也已经被废弃

extension UITableView {
    struct once{
        static var onceTaken:Int = 0
    }
    dispatch_once(&once.onceTaken) { () -> Void in
    //在这里dispatch_once就会报错
        //此处省略1000000行代码    
    }
}
解决方法: 通过给DispatchQueue添加扩展实现
extension DispatchQueue {
    private static var _onceTracker = [String]()
    public class func once(token: String, block: () -> ()) {
        objc_sync_enter(self)
        defer {
            objc_sync_exit(self)
        }
        if _onceTracker.contains(token) {
            return
        }
        _onceTracker.append(token)
        block()
    }
    
    func async(block: @escaping ()->()) {
        self.async(execute: block)
    }
    
    func after(time: DispatchTime, block: @escaping ()->()) {
        self.asyncAfter(deadline: time, execute: block)
    }
}

使用字符串token作为once的ID,执行once的时候加了一个锁,避免多线程下的token判断不准确的问题。
使用的时候可以传token

 DispatchQueue.once(token: "tableViewOnce") {
     print( "Do This Once!" )  
 }

或者使用UUID也可以:

private let _onceToken = NSUUID().uuidString
  
DispatchQueue.once(token: _onceToken) {  
    print( "Do This Once!" )  
}
  • 后续又遇到别的问题会继续更新
  • 文章中如有解释不足之处,还望多多指教
Xcode升级到8.0,Swift3.0之后,出现的alamofire问题 前两天,刚刚升级了Xcode到8.0, swift3.0, 然后运行项目就崩溃了,我的程序报了200多个错。 个人建议:刚开始使用Xcode8打开之前的项目会有很多问题,所以建议大家把Xcode7的版本也保留上 首先先给电脑上现有的Xcode改名,比如Xcode7.3.1,然后APP Store上继续更新Xcode,安装完成后会保留两个版本。 当你更新Xcode8.0之后,你需要Conv 阅读详情

相关推荐

OpenStack版本升级之Swift

Swift升级的一般流程 Swift升级的一般流程见参考文档,摘抄如下: As always, a production Swift cluster can be upgraded live, with no downtime for clients. The normal upgrade path is: Stop the background processes Upgr

ugyn109的专栏 2208

Swift中使用 +load 和 +initialize

+load 和 +initialize 方法是我们写 Objective-C 代码时常用的两个方法,不过貌似在 Swift 4.x 后,这两个方法在 Swift 类中不那么好使,会报如下编译错误: Method 'load()' defines Objective-C class method 'load', which is not permitted by Swift Method 'initialize()' defines Objective-C class method 'initialize

gcs的博客 3246

Xcode9 在Swift 4.0下编译时第三方框架报错Swift compiler Error的解决方案

更多原创文章,请访问:https://takioo.cn 随着 Xcode9 Swift 4.0 的到来,一些小问题也接踵而至。   许多优秀的 Swift 第三方框架还没有来得及迎接 Swift 4.0 的到来,它们还停留在 Swift3.x 的状态。 这个时候新建一个项目,使用cocoapods 引入所需的第三方,即使 pod install 成功后,一编译工程就是满屏红, 且报错 ...

魏莉的微博客 4180

Objective C类方法load和initialize(关于它们的执行时环境与load调用对父类initialize方法的影响)

过去两个星期里,为了完成一个工作,接触到了NSObject中非常特别的两个类方法(Class Method)。它们的特别之处,在于iOS会在运行期提前并且自动调用这两个方法,而且很多对于类方法的规则(比如继承,类别(Category))都有不同的处理。 而因为这两个方法是在程序运行一开始就被调用的方法,我们可以利用他们在类被使用前,做一些预处理工作。比如我碰到的就是让类自动将自身类名保存到一个N...

realyezi的博客 658

2025软考信息安全工程师真题

2025信息安全工程师软考真题

qq_40424393的博客 1707

LeGO-LOAM运行kitti数据集

文章目录1. kitti-lego-loam2. 改动3. 实验结果4. evo轨迹测评 1. kitti-lego-loam 链接:kitti-lego-loam kitti-lego-loam提供了将kitti序列转化成rosbag的代码,在kittibag中. 需要注意下数据文件的存放顺序,以00序列为例: datafolder          |____results          &

Zlp19970106的博客 8703

swift4.0 适配

一、前言在我们的工程中处于swift和OC混编的状态,使用swift已经有一年半的时间了,随着Xcode9的更新,swift3.2和swift4.0也随之到来,swift3.2相较于Xcode8的swift3.1变动极小,适配没遇到问题,主要关注swift4.0的适配。 二、查看当前工程的 swift 版本image.png 三、使用 Xcode 将工程转换到 swift4.01、环境 Xcode...

weixin_33982670的博客 390

RK3566基于Buildroot定制QT开发环境的完整指南

本文详细介绍了如何在RK3566开发板上使用Buildroot定制QT开发环境的完整流程。从基础环境搭建、Buildroot初始配置到QT模块选择与编译验证,提供了实战经验和常见问题解决方案,帮助开发者高效完成嵌入式Linux下的QT开发环境部署。

weixin_26804345的博客 358

Objective-C——initialize方法调用原理分析

一、调用时机 在类第一次接收到消息的时候调用 二、调用顺序 先调用父类的initialize方法,再调用子类的initialize方法(递归,每个类只会初始化一次) 如果子类没有实现initialize方法,则会调用父类的initialize方法(消息调用机制,通过superclass指针向上查找)(所以,父类的initialize方法可能会被调用多次) 如果分类实现了initialize方法,会“覆盖”类本身的initialize调用(方法合并的时候,分类的方法更靠前) 三、源码窥探 // obj

Cheny的博客 1880

深度解构事务码 SQF:Support Query Framework 与 ABAP 静态分析实战

某制造企业在年度审计前,需要确认自定义发票过账程序 ZFI_INV* 系列是否存在硬编码公司代码与未捕获异常。技术团队在字段填入ZFI_INV*后,勾选与规则,执行扫描。SQF 生成的 ALV 报告列出 42 个警告,其中 17 条与抛出 CX_SY_NO_HANDLER 相关,8 条涉及动态 SQL 注入风险。结果导出至 Excel 供开发整改,并在 ATC 阶段验证修复。此过程较手工逐个执行 Code Inspector 节省超 80 % 时间。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 215

算法 | A*算法实现最优路径规划

启发式探索是利用问题拥有的启发信息来引导搜索,达到减少探索范围、降低问题复杂度的目的。A*寻路算法是启发式探索的一个典型实践,在寻路搜索的过程中,给每个节点绑定了一个估计值(即启发式),在对节点的遍历过程中采取估计值优先原则,估计值更优的节点会被优先遍历。...

不断学习,不断进步,提高自己 6629

「 iOS知识小集 」2018 · 第 41 期

原文链接 上周公众号发布的以下文章: iOS 启动时间优化 腾讯体育iOS客户端逆向实践 脑洞大开:为啥帧率达到 60 fps 就流畅? 快速用上 Swift 静态库 本期知识小集的主要内容包括: 一入IAP深似海第二弹 Xcode 10 / iOS 12 获取 WiFi 信息 Swift 4.x 中使用 +load 和 +initialize SecRandomCopyBytes 生成伪随...

zsxjtip的博客 295

STM32F767 GPIO跑马灯工程从零搭建指南

嵌入式开发中,基于HAL库的STM32工程初始化是确保外设可靠运行的基础环节。其核心在于理解芯片时钟树配置原理、GPIO工作模式与硬件电气特性之间的映射关系。正确启用RCC时钟源、合理分配AHB/APB总线分频系数,可保障系统主频稳定;而精准设置推挽输出、上下拉状态及引脚速度,则直接影响LED等基础外设的驱动可靠性。结合STM32CubeMX图形化配置工具,开发者能将寄存器级操作抽象为可视化流程,显著提升工程可追溯性与复用性。本文以STM32F767IGT6和阿波罗开发板为载体,详解从Repository固

weixin_42453228的博客 61

升级Swift4 0遇到的坑

升级Swift4.0 并不是所有库都能做到及时支持Swift4.0,更何况是在现在连Xcode9也还是beta的状态 所以我们仅能做到将自己的业务代码(主工程代码)部分升级到Swift4.0,然后同时保留各种pod库在Swift3.2版本。 没办法,谁叫Swift4.0也还无法做到API兼容呢(但愿能在Swift5之前实现吧)。 至于我说的同时使用两个版本的Swift,这是没问题的,Xcode9...

weixin_33971130的博客 843

paddle 43 用onnxruntime实现ppyoloe模型的部署(含python和c++版本)

PP-YOLOE+是PP-YOLOE模型的升级版,PP-YOLOE+_l在COCO test-dev2017达到了53.3的mAP, 同时其速度在Tesla V100上达到了78.1 FPS。PP-YOLOE+_s/m/x同样具有卓越的精度速度性价比。paddle官方只给出了基于paddle框架的部署案例,为了更好的部署,为此实现将paddle模型转换为onnx模型,然后在python下实现onnxruntime部署。后续会补充c++ onnxruntime部署

a486259的博客 1914

9篇6章7节:SEER 数据库的2025年数据变量多条件组合选择(2026年版)

软件中的病例筛选功能通过CaseSelection界面实现精准研究队列构建。该界面允许用户通过变量选择(Variable)、运算符定义(Operator)和取值设定(Values)三步操作创建筛选条件,支持种族、分期等关键变量的多条件组合。

MD Code 1454

升级由swift2.3->swift4.0

本次升级由swift2.3->swift4.0 swift2.3升级swift3.0 pravite -> fileprivate Publice -> open 枚举更换小写 方法名更精简,后面括号移除 gcd方法改变 gcdtimer创建方法返回值类型变了 DispatchSource -> DispatchSourceTimer setTimer(start: Dis

leafgw的专栏 3337

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

ActiveLabel.swift版本升级指南:从Swift 4.2到Swift 5.0的平滑迁移

ActiveLabel.swift是一个功能强大的UILabel替代库,支持话题标签(#)、用户提及(@)、链接(http://)和自定义正则模式的高亮显示与交互。随着Swift 5.0的发布,项目也进行了相应的版本升级,本指南将帮助开发者顺利完成从Swift 4.2到Swift 5.0的平滑迁移。🚀 ## 为什么需要升级到Swift 5.0? Swift 5.0带来了更好的性能、更稳定的A

gitblog_01179的博客 856

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

swift3.0转4.0遇到的坑

我们以斗鱼APP为例,总结swift3.0以及swift4.0转换过程中遇到的问题。 一、方法重写问题 1、swift 3.0在子类中的方法重写 我们RecommendVC类继承自BaseAnchorVC,BaseAnchorVC中包含setupUI方法,我们重写setupUI方法,然后再子类RecommendVC中重写setupUI方法。 extension RecommendV...

xiaoxiaocode的博客 1804

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Swift3.2升级Swift4.2填坑建议(自动处理小工具/脚本)

前提: 最近(2019.04)处理了项目的Swift版本升级,痛苦的经历,写了一个小工具分享一些心得给大家,希望有所帮助。 公司项目是Swift3.2和Object-C混编,引用了很多三方库,三年以上迭代

m0_37892360的博客 810

XCode10 swift4.2 适配遇到的坑

以下是2018年10月23日更新 经过大约一个月的时间的适配,项目正式使用XCode10(以下简称为10 or XC10)大部分库都升级为Swift4.2(以下简称为 4.2 or S4.2),下面是适配过程中遇到的一些坑。 1. Swift4、Swift4.2混编 如果你对项目是小的独立项目,完全可以全部升级为4.2,你可以略过第一条;如果你依赖了一些第三方的库,且没有升级4.2...

diansuoku1565的博客 734

Swift版本升级的正确姿势

以swift4.0升级到4.2为例: 1、确保在swift4.0情况下能够成功编译运行 2、选择Edit -&gt; Convert -&gt; To Current Swift Syntax… 让Xcode帮我们把Swift4.0的代码转换为Swift4.2(升级Xcode后第一次编译,Xcode会自动提醒你升级swift版本,点那个也行),选择转换的时候不要选择pod的第三方框架,pod的...

chokshen的博客 8387

cocoapods升级到1.1.0,为了使用Swift3.0,遇到的问题

1.升级cocoa pods 原因是0.39.0中,swift3.0不能使用,所以必须升级 gem install cocoapods --pre //升级到最新版本 这样升级会报错的: While executing gem ... (Errno::EPERM) Operation not permitted - /usr/bin/pod Cocoapods在10.11

WUYANYANstrong的博客 1263

SwipeCellKit版本迁移指南:从Swift 4到Swift 5的平滑升级

SwipeCellKit是一个基于Swift实现的滑动UITableViewCell和UICollectionViewCell的开源库,灵感来源于苹果官方邮件应用的设计。随着Swift语言的不断演进,从Swift 4升级到Swift 5是每个iOS开发者都需要面对的重要任务。本文将为您提供完整的版本迁移指南,帮助您顺利完成这一关键升级过程。🎯 ## 为什么需要升级到Swift 5? Swif

gitblog_00530的博客 513

swift3.2升级到swift4.0 扫码不走回调方法

xcode升级到9.0 swift改到swift4.0之后扫码一直不走回调 ,研究了好长时间,发现苹果把扫码的代理方法的参数变了之前的方法 func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCa

SMHDream的博客 1757
上一篇: JavaScript基本语法01
下一篇: iOS之Scanner基本用法
CodeTitan
博客等级 码龄9年 51粉丝 102原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值