
首先,dispatch 的全局函数不再写为下划线风格的名称了,它变成了一个更符合 Swift 风格的 dispatchQueue 的样子。
main thread同样的,你不需要在去用dispatch_get_main_queue()来获取主线程,而是dispatchQueue.main,那么要放到主线程的代码怎么执行呢?只需要在线程后边使用.async{}即可,也就是说,大概是这样:
<span >dispatchQueue</span>.main.async { [weak <span >self</span>] <span >in</span>yourcoderunsin mainthread} 优先级 说完了最基本的东西,我们再来说说其他改变了的东西,比如优先级的名字。
我们知道,GCD 的默认队列优先级有四个:
disPATCH_QUEUE_PRIORITY_HIGH disPATCH_QUEUE_PRIORITY_DEFAulT disPATCH_QUEUE_PRIORITY_LOW disPATCH_QUEUE_PRIORITY_BACKGROUND现在,新的语法当中,改变了这四个不明不白的优先级名称为更有意义的名字:
.userInitialted .default .utility .background当然,它们的对应关系也就是与顺序相同的:
disPATCH_QUEUE_PRIORITY_HIGH:.userInitiated disPATCH_QUEUE_PRIORITY_DEFAulT:.<span >default</span> disPATCH_QUEUE_PRIORITY_LOW:.utility disPATCH_QUEUE_PRIORITY_BACKGROUND:.background获取一个队列
我们使用dispatchQueue.global()获取一个系统的队列,这样的话获取的就是默认.default优先级的队列了,如果要获取其他优先级的队列,就使用dispatchQueue.global(qos:.userInitiated),最后,我们使用.async{}来执行代码:
dispatchQueue.<span >global</span>(qos: .userInitiated).async {<span >//your code here</span>} 创建一个队列 直接用dispatchQueue的初始化器来创建一个队列。最简单直接的办法是这样:
<span >let</span> queue = dispatchQueue(label: <span >"myBackgroundQueue"</span>)
复杂一点?你可以指定优先级以及队列类别:
<span >let</span> queue = dispatchQueue(label: <span >"myBackgroundQueue"</span>,qos: .userInitiated,attributes: .concurrent)
然后把代码放进去即可:
[PHP] view plain copy queue.async{ <spanclass="keyword"style="Font-weight:bold">print</span>(<spanclass="string"style="color:rgb(221,17,68)">"aaa"</span>) } 队列打组对于组,现在你可以使用这样的语法直接创建一个组:
<span >let</span> <span >group</span> = dispatchGroup()
至于使用,则是这样的:
<span >let</span> <span >group</span> = dispatchGroup()<span >let</span> queue = dispatchQueue(label: <span >"myBackgroundQueue"</span>)queue.async(<span >group</span>:<span >group</span>) {print(<span >"background working"</span>)} 那么,如果有多个并发队列在同一个组里,我们需要它们完成了再继续呢?
<span >group</span>.wait()指定时间后执行
很多时候你可能还需要让一些代码在指定的时间后执行,比如动画完成后。这个任务在swift 2.3 很麻烦,不过,在3.0就不一样了:
dispatchQueue.main.asyncAfter(deadline: dispatchTime.Now() + <span >3.0</span>) {<span >print</span>(<span >"after!"</span>)} 只需要一句话即可。
其他变化:
升级到 Swift 3
在升级到 Swift 3 时,你会发现,基本上每个文件都需要改动!之所以这样,是因为所有的 Cocoa API 名称都被改变了。简而言之,API 仍然是原来的 API,但这个 API 在 Objective-C 中是一种叫法,而在 Swift 中又是另一种叫法了。Swift 3 语法书写起来要更贴近于自然语言。
在 Xcode 8 中苹果提供了 Migration Assistant,它可以完成大部分的迁移工作。但很显然,仍然有一部分工作需要你手动完成。
你可以立即将代码升级到 2.3 或者 3.0。如果你需要将代码又转回来,你可以用 Xcode 的 Edit > Convert > To Current Swift Syntax… 菜单。编译器会和 Migrateion Assistant 一样智能。如果你在调用方法时,偶然使用了老的 API,编译器会显示一个 Fixt-It 选项,让你使用正确的新 API。幸好 Swift 3 在最终发布时,才会停止改变源代码。因此,你可以将你的 Swift 代码保存为不同的版本。但是 Swift 核心团队不能保证这一点以后不会改变,如果在某个时候不在保证源码上的兼容,他们会提供一个较长的过渡期。这意味着源码是稳定的,这样能鼓励更多的保守的公司去使用它。
这也说明,二进制稳定的目标还没有达到。本文最后将讨论这将导致的影响。
Swift 3 中最大的改变是标准库中在每个库中都采用了统一命名方式。API Design Guidleines中包含了这些规则,核心团队在构建 Swift 3 时采用了这些规则,对新手来说,这高度增强了可读性和易用性。核心团队遵循的是”好的 API 设计应当总是从调用者的角度看待问题“的原则。他们努力让 API 简单易用。不再多说,让我们开始介绍这些对你来说非常重要的改变。
第一个参数的 label让我们从你每天都会在 Swift 中用到的例子开始。
在函数或方法中的第一个参数现在必须有一个 label ,除非你显式地声明不要。以前,我们调用一个函数或方法时,可以忽略第一个参数的 label[SE-0046]:
<code ><span >//</span> 第一句是 Swift <span >2</span> 语法,第二句是 Swift <span >3</span> 语法<span >"RW"</span>.writetofile(<span >"filename"</span>,<span >atomically</span>: <span >true</span>,<span >enCoding</span>: NSUTF8StringEnCoding)<span >"RW"</span>.write(<span >tofile</span>: <span >"filename"</span>,<span >atomically</span>: <span >enCoding</span>: NSUTF8StringEnCoding)SKAction.rotateByAngle(CGfloat(M_PI_2),0);">duration</span>: <span >10</span>)SKAction.rotate(<span >byAngle</span>: CGfloat(M_PI_2),<span >duration</span>: <span >10</span>)UIFont.preferredFontForTextStyle(UIFontTextStyleSubheadline)UIFont.preferredFont(<span >forTextStyle</span>: UIFontTextStyleSubheadline)overrIDe func numberOfSectionsIntableVIEw<span ><span >(tableVIEw: UItableVIEw)</span> -></span> IntoverrIDe func numberOfSections<span ><span >(<span >in</span> tableVIEw: UItableVIEw)</span> -></span> Intfunc vIEwForZoomingInScrollVIEw<span ><span >(scrollVIEw: UIScrollVIEw)</span> -></span> UIVIEw?func vIEwForZooming<span ><span >(<span >in</span> scrollVIEw: UIScrollVIEw)</span> -></span> UIVIEw?NSTimer.scheduledTimerWithTimeInterval(<span >0.35</span>,0);">target</span>: self,0);">selector</span>: <span >#selector(reset),userInfo: nil,repeats: true)</span>NSTimer.scheduledTimer(<span >timeInterval</span>: <span pre-numbering" ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li><li >10</li><li >11</li><li >12</li><li >13</li><li >14</li><li >15</li><li >16</li><li >17</li><li >18</li><li >19</li><li >20</li></ul>
注意,有些方法使用介词“of”、“to”、“with”、“in”作为外部参数名。这是为了增加代码的可读性。
如果这个方法不使用介词也不使用 label,你应该在方法定义时,显式地在第一个参数名之前加一个下划线:
<code >overrIDe func tableVIEw(_ tableVIEw: UItableVIEw,numberOfRowsInSection section: Int) -> Int { <span >...</span> }overrIDe func dIDMovetoVIEw(_ vIEw: SKVIEw) { <span >...</span> }</code><ul ><li >1</li><li >2</li></ul> 在许多编程语言中,许多方法可以共用一个方法名,但参数名不同。Swift 也不例外,现在,你可以重载方法,APIs 能够将直接将它们转换成合适的调用。下面是一个例子,展示了 index() 方法的两种重载形式:
<code ><span >let</span> names = [<span >"Anna"</span>,<span >"barbara"</span>]<span >if</span> <span >let</span> annaIndex = names.index(<span >of</span>: <span >"Anna"</span>) { print(<span >"barbara's position: \(names.index(after: annaIndex))"</span>)}</code><ul ><li >1</li><li >2</li><li >3</li><li >4</li></ul> 方法名是同一个,但参数名不同,这将让人更容易记忆。
省略不必要的单词过去,在苹果标准库中,方法名中会包含一个单词,用于表明方法的返回值。因为 Swift 编译支持类型推断,这种做法其实并不必要。核心团队尽可能过滤一切“噪音”,因此将这些重复的单词都删除了,只留下方法名中最重要的部分。
在将 Objective-C 库转换成本地 Swift 语言方面,API 变得更智能了[SE-0005]:
<code >// 第一句是 Swift <span >2</span> 语法,第二句是 Swift <span >3</span> 语法let blue = UIcolor<span >.bluecolor</span>()let blue = UIcolor<span >.blue</span>let min = numbers<span >.minelement</span>()let min = numbers<span >.min</span>()attributedString<span >.appendAttributedString</span>(anotherString)attributedString<span >.append</span>(anotherString)names<span >.insert</span>(<span >"Jane"</span>,atIndex: <span >0</span>)names<span hlJs-number" >0</span>)UIDevice<span >.currentDevice</span>()UIDevice<span >.current</span>()</code><ul ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li><li >10</li><li >11</li><li >12</li><li >13</li><li >14</li><li >15</li><li >16</li></ul>新的 GCD 和 Core Graphics
一提到遗留下来的“元老级” API,GCG 和 Core Graphics 更需要被重新“装扮一新”。
Grand Central dispatch 常用于长时间计算或者与服务器通讯。将任务放到不同的线程,你可以避免阻塞用户界面。libdispatch 库是用 C 语言编写的,提供了 C 风格的 API。这个 API 现在在 Swift 中被重新设计为[SE-0088]:
<code ><span >// Swift 2 语法</span><span >let</span> <span >queue</span> <span >=</span> dispatch_queue_create(<span >"com.test.myqueue"</span>,nil)dispatch_async(<span >queue</span>) { print(<span >"Hello World"</span>)}<span >// Swift 3 语法</span><span >=</span> dispatchQueue(label: <span >"com.test.myqueue"</span>)<span >queue</span><span >.</span>async { print(<span >"Hello World"</span>)}</code><ul ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li><li >10</li><li >11</li></ul> 类似的情况还有 Core Graphics。Core Graphics 是用 C 编写的,曾经以来一直只能以“丑陋”的函数方式调用。这是它的新的用法[SE-0044]:
枚举中 case 值的大小写另一个和过去的 Swift 代码不同的地方是,在枚举中定义的 case 值现在使用小驼峰命名法。这是为了和属性名或者变量名保持一致[SE-0006]:
大驼峰命名法现在只在类型名和协议名上使用。当你习惯这一切之后,Swift 团队对于追求一致性的努力才没有白费。
返回值的方法或者修改值的方法标准库中对方法名中使用动词和名词的规定也更加统一。你应当根据这个方法会导致什么后果或者要采取一些动作来进行方法命名。首要原则是如果这个方法名中包含“ed”或“ing”后缀,则表明这是一个名词。方法名为名词的方法有返回值。如果不包含这些后缀,则很可能这是一个动词。以动词命名的方法会对某块引用的内存进行一些 *** 作。即所谓的“修改某个值”。下面是几个符合名词/动词命名规则的方法[SE-0006]:
下面是一些使用这些方法的代码片段:
<code >var ages = [<span >21</span>,<span >10</span>,102); Box-sizing: border-Box;">2</span>]<span > // 变量,不是常量,这样你才能修改它</span>ages.<span >sort</span>()<span > // 修改值,现在值变成了 [2,10,21]</span><span >for</span> (index,age) <span >in</span> ages.enumerated() {<span > // "-ed" 是名词,表示会返回一个 ages 拷贝</span> print(<span >"\(index). \(age)"</span>)<span > // 打印:1. 2 \n 2. 10 \n 3. 21</span>}<span >###函数类型</span>函数在声明和调用时,都需要用括号将参数括住:```swiftfunc f(<span >a</span>: Int) { ... }f(<span >5</span>)<<span >div</span> class=<span >"se-prevIEw-section-delimiter"</span>></<span >div</span>></code><ul ><li >1</li><li >2</li><li >3</li><li >4</li><li >5</li><li >6</li><li >7</li><li >8</li><li >9</li><li >10</li><li >11</li><li >12</li><li >13</li><li >14</li><li >15</li><li >16</li><li >17</li><li >18</li><li >19</li><li >20</li><li >21</li></ul>但是,当你用函数类型作为参数时,你可能会写出这样的代码:
你会发现代码很难读懂。参数在哪里结束,返回值从哪里开始?在 Swift 3 中,正确的定义方法是[SE-0066]:
现在,参数列表被括号包裹,然后才是返回类型。事情变得简单,同时函数类型更容易被识别出来。通过下面的比照,你会更清楚:API 的增强除了对已有 API 进行“旧瓶新装”这个最大的改变以外——有非常多的 Swift 社区正致力于此,也有对 Swift API 的一些功能上的增加。
访问所属类型当你定义一个静态属性或方法时,你直接通过类或类型来调用它们:
<code >CustomStruct.staticmethod()<<span >div</span> <span >class</span>=<span >"se-prevIEw-section-delimiter"</span>></<span >div</span>></code><ul > 如果你当前正在编写类型内部的代码,你还是要使用类型名来调用静态方法。为了使表述更加清晰,现在你可以通过 Self 来引用当前实例所属类型。S 为大写的 Self 表示引用当前实例的类型,而 s 为小写的 self 则引用当前实例自身。这是具体的例子[SE-0068]:
行内 Sequencessequence(first:next:) 以及 sequence(state:next:) 是全局函数,返回一个无限序列。你传给它们一个初值或一个可变的状态,它们会在稍后调用闭包中的代码[SE-0094]:
还可以用 prefix *** 作符来为序列加一个限制[SE-0045]:
<code >for</span> x <span >in</span> sequence(first: <span >0.1</span>,next: { <span ></span> * <span >2</span> }).prefix(<span >while</span>: { <span ></span> < <span >4</span> }) { <span >// 0.1,0.2,0.4,0.8,1.6,3.2</span>}</code><ul ><li >1</li><li >2</li><li >3</li></ul>杂项 #keyPath() 等同于 #selector() ,帮助你减少输入错误 你可以在某些类型上调用 pi,比如:float.pi、CGfloat.pi。大部分时候编译器能够推断出类型:let circumference = 2 * .pi * radius [SE-0067] NS 前缀从老的 Foundation 类型中移除,现在可以用 Calendar、Date来替代 NSCalendar、NSDate 了 工具的改善Swift 只是一门语言,大部分时候你都无法离开书写它的开发环境——对于苹果开发者来说,也就是 Xcode!工具上的改变影响着每天编写代码的方式。
改善了字符串的 Hash 算法,导致在将字符串存入字典后,性能有 3 倍的提升 将对象从堆移到栈中存放,导致性能有 24 倍的提升(某些情况下) 编译器可以一次缓存多个文件(在整个模块被优化过的情况下) 优化了代码的大小,导致 Swift 代码的编译尺寸更小。以苹果的 Demobots 为例,编译尺寸缩减了原大小的 77%。
Swift 3 修正了编译器和 IDE 中的 BUG,还改善了报告错误和信息的精确性。就像你所期望的,每个版本的发布都会让 Swift 和编译器的运行变得更快:Xcode 也会更加智能地理解 Swift 代码:
过去,当你在一个 API 方法比如 sort() 上右击并跳转到定义时,你会看到一个不太容易理解的头文件。现在,在 Xcode 8 中,你会看到 sort() 方法实际上是 Array 类的扩展。
总结以上是内存溢出为你收集整理的swift3.0 gcd 变化全部内容,希望文章能够帮你解决swift3.0 gcd 变化所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)