Swift 3.0 项目升级实战

作者: 效宇笑语 | 来源:发表于2017-02-06 22:39 被阅读762次
  • dispatch_once方法废弃,可以使用如下两种方式实现:

public extension DispatchQueue {
private static var _onceTracker = String
/**
Executes a block of code, associated with a unique token, only once. The code is thread safe and will
only execute the code once even in the presence of multithreaded calls.
- parameter token: A unique reverse DNS style name such as com.vectorform.<name> or a GUID
- parameter block: Block to execute once
*/
public class func once(token: String, block:()->Void) {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
if _onceTracker.contains(token) {
return
}
_onceTracker.append(token)
block()
}
}

第二种方式是苹果推荐的方式(xCode自动将swift升级时,几乎所有的dispath_once方法都会自动转换成下面这种形式),代码如下:

var t: SomeObject?
private static var __once: () = {
//此处做一次性操作
t = SomeObject()
}()

如果仅仅是需要单例模式的话可以通过如下代码实现(static let 标记的常量,为线程安全的,并且是懒加载,只赋值一次):

class SingleInstanceTest {
static let sharesdInstance = SingleInstanceTest()
private override init() {
// 注册通知等关初始化操作
}
}

  • CGSize、CGPoint、CGRect 的make方法取消,需要使用CGSize(width: 1, height: 1)等方式创建
  • 很多原来的方法如systemFontOfSize都将最后的单词变为方法的外部参数名:UIFont.systemFont(ofSize: kGlobalFontSize_H)
  • UIColor等类型的类方法都变为静态属性:

UIColor.redColor() -> UIColor.redColor
UIColor.clearColor() -> UIColor.clearColor

  • 绘制直线等CoreGraphics操作由之前的CGPathMoveToPoint、CGPathAddLineToPoint变为path.move、path.addLine等,参数不变(大多数CoreGraphics的方法调用都显得更swift化,可以查看相关文档)。
  • 如果方法带有返回值,例如

func sum(a: Int , b: Int) -> Int {
return a + b
}

如果不需要返回值可以通过 _ = sum(a: 5 , b: 6)来避免警告。

  • String与NSString必须显示转换例如,如下代码会报错:

func say(a: NSString) {
print(a)
}
var d : String = "hello"
say(a: d)

此时需要将变量d显式转换为NSString

  • NSDateFormatter、NSNumberFormatter、NSBundle等被彻底废弃,需要使用DateFormatter和NumberFormatter、Bundle等代替,同时苹果推出Date、Data、Calendar等swift类型(去OC化正在紧张进行中,如果苹果推出新的swift类型可以替代OC,可能会将原OC类型禁用掉,那么为了以后swift升级降低代码的修改量,建议使用swift的类型)。
  • GCD更swift化,swift3.0中可以使用DispatchQueue获取主线程、global线程或者创建单独的线程,线程任务的提交可以通过DispatchQueue的asyn、syn等(注意:通过指定线程优先级获取的global线程方法已经将要废弃,可以通过使用global(qos:_)->DispatchQueue创建)。
  • swift 3.0中对数组的操作例如:插入、删除、判断是否包含的相关方法更简洁:insert(: , at:)、remove(at: )、contains(: )
  • swift 3.0中获取类的名称(类型)需要通过 type(of: _)方法获得,如下代码所示:

class Person {
class func className() -> String {
return String(describing: self)
}
func typeS () -> String {
return String(describing: type(of: self))
// type(of: _)相当于dynamicType
}
func typeO () -> Person.Type {
let c = type(of: self)
return c
}
}
var c = Person().typeS()
var d = Person.className()
var o = String(describing: Person().typeO())

  • swift3.0 中 UIControl的状态(Normal、Disable、Highlight等)被封装到一个结构体中,并且该结构体实现了OptionSet协议,该协议用于掩码运算(注意:xCode会自动将.normal状态变为UIControlState(),可以修改为.normal)。
  • swift3.0 的取余运算:在xcode转换swift版本时,会将取余运算符% 变为truncatingRemainder(dividingby:_),进入文档看了一下swift3.0的标准库中多了许多的算数方法。
  • swift3.0通知变更,通知中心由NSNotificationCenter 变为 NotificationCenter,并且post与addObject方法中的key参数由NSNotification.Name代替,变化如下所示:
// swift 2
NSNotificationCenter.defaultCenter().postNotificationName("kLogoutNotification", object: nil)
// swift 3
NotificationCenter.default.post(name: NSNotification.Name.init(rawValue: "kLogoutNotification"), object: nil)
  • swift 3.0方法外参的变化,第一个参数也需要指定一个外参数(外参数为调用处显示的参数,内参数是在函数内使用的参数),如果不指定外参数,需要有通配符替代,代码如下所示:

// swift 2 的写法,方法第一个外参数,可以不需要显示给出
func Say(p: Int , two: Int , _ three: Int) {
print("(p)")
print("(two)")
print("(three)")
}
// swift 3 的写法,必须显示给出第一个参数的外参数,否则编译报错
func Say(_ p: Int , two: Int , _ three: Int) {
print("(p)")
print("(two)") // 第二个参数two可同时做内参数与外参数
print("(three)") // 通配符代替第三个参数,调用处可以不显示外参数
}
Say(p: 0, two: 1, 2) //

  • swift 3.0 枚举的变化,xCode升级swift时,会将所有的枚举类型的值得首字母变为小写(不强制,最好还是按照这个规则进行编码),代码如下:

enum SchoolRange: Int {
case default = 1
case province
case city
case nation
func title() -> String {
switch self {
case .province:
return "省级"
case .city :
return "市级"
case .nation:
return "国家级"
default:
return "县级"
}
}
}

  • swift3.0中的泛型可以获取OC中泛型的类型,如果在OC中使用了泛型,那么在swift与OC的混编中,swift可以推测泛型占位符的类型,如下代码所示。
// OC 泛型定义
// OC 代码
@interface Person<T>
{
    id _typeCode;
} 
- (T)typeCode;
@end
@interface Student 
- (Person<School>)typeCodeSchool;
@end
// swift 2.2
var s: Student = Student()
var c = s.typeCodeSchool() //c的类型为Person
// swift 3.0
var s: Student = Student()
var c = s.typeCodeSchool() //c的类型为   Person<School>
  • private 和 fileprivate:在swift3中private的作用域缩小了,仅能在当前的大括号内被访问,而fileprivate仅能在当前文件中被访问,如下代码所示
// swift 2中 同一文件可以访问private标记的变量
class Person {
    private var name: String!
}
class Student {
    func testPer(p: Person) {
        p.name = "Hello"   // swift 2中private标记的变量,可以被同一文件内的任何类、方法访问
    }
}
// swift 3中private标记的变量只能被{}中的方法等访问
class Person {
    private var name: String!
    fileprivate var age: Int!
}
class Student {
    func testPer(p: Person) {
        p.age = 32  // swift3中fileprivate标记的变量可以在本文件中的任何位置访问
        p.name = "Hello"   // 此处编译错误
    }
}
  • swift3.0中的Bool类型的变量名前都加上了is如isEnable、isHidden等
  • swift3.0中新增open关键字,被open标记的变量可以被不同的module的类继承、重写,public标记的变量或者类可以被当前module的类继承、重写,默认情况下internal不可以被继承或者重写。
  • swift3.0中的逃逸闭包,如果闭包被作为参数传递到函数时,该闭包不需要立即执行而是需要等某些线程完成任务之后再执行,那么需要在该闭包前加上@escaping,否则编译器报错。如下代码所示:

//以下函数是当动画页面动画结束之后执行一个闭包
func animationAfter(completion: @escaping () -> Void) {
UIView.animate(withDuration: 0.3, animations: {
// do some animation
}) { (isCom) in
completion()
}

相关文章

网友评论

  • 863c73f31933:楼上,这个问题还有些复杂,在一个工程中,进行合并工程,合并的工程是使用oc封装的.a库工程,在swift合并该工程到swift工程中很多oc的xx.pch头文件中的类名没找到,这个如何解决有思路吗?
    效宇笑语:@SunlightInMyLif 报的什么错误能粘给我看看么?
    863c73f31933:@SundayBoyDiDi 你好,我这边已经配置了且使用该桥接类了,这边的保错是在swift2.3升级swift3.0的时候报的,之前2.3的时候,这里没有问题,可以识别另一个工程中的.pch文件
    效宇笑语:swift 如果想要使用自定义OC的类,需要创建bridge-Header.h文件,并在bridge-Header.h文件中import需要的类,可以通过自动创建该文件:在项目中随意创建一个OC文件,提示是否创建bridge-header选择创建,或者手动配置(在target的build Setting选项卡中的Swift Complier - Gerneral 下面可以配置bridge-Header.h的文件位置,并将insatall Objective-C Compatibility Header 设置为Yes)

本文标题:Swift 3.0 项目升级实战

本文链接:https://www.haomeiwen.com/subject/ybouittx.html