色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何使用Swift提高代碼質(zhì)量

OSC開源社區(qū) ? 來源:京東云開發(fā)者 ? 2023-05-19 09:42 ? 次閱讀

一、前言

京喜APP最早在2019年引入了Swift,使用Swift完成了第一個(gè)訂單模塊的開發(fā)。之后一年多我們持續(xù)在團(tuán)隊(duì)/公司內(nèi)部推廣和普及Swift,目前Swift已經(jīng)支撐了70%+以上的業(yè)務(wù)。通過使用Swift提高了團(tuán)隊(duì)內(nèi)同學(xué)的開發(fā)效率,同時(shí)也帶來了質(zhì)量的提升,目前來自Swift的Crash的占比不到1%。在這過程中不斷的學(xué)習(xí)/實(shí)踐,團(tuán)隊(duì)內(nèi)的Code Review,也對(duì)如何使用Swift來提高代碼質(zhì)量有更深的理解。 二、Swift特性

在討論如何使用Swift提高代碼質(zhì)量之前,我們先來看看Swift本身相比ObjC或其他編程語言有什么優(yōu)勢(shì)。Swift有三個(gè)重要的特性分別是富有表現(xiàn)力/安全性/快速,接下來我們分別從這三個(gè)特性簡(jiǎn)單介紹一下:

富有表現(xiàn)力

Swift提供更多的編程范式和特性支持,可以編寫更少的代碼,而且易于閱讀和維護(hù)。

基礎(chǔ)類型- 元組、Enum關(guān)聯(lián)類型

方法-方法重載

protocol- 不限制只支持class、協(xié)議默認(rèn)實(shí)現(xiàn)、類專屬協(xié)議

泛型-protocol關(guān)聯(lián)類型、where實(shí)現(xiàn)類型約束、泛型擴(kuò)展

可選值- 可選值申明、可選鏈、隱式可選值

屬性- let、lazy、計(jì)算屬性`、willset/didset、Property Wrappers

函數(shù)式編程- 集合filter/map/reduce方法,提供更多標(biāo)準(zhǔn)庫方法

并發(fā)- async/await、actor

標(biāo)準(zhǔn)庫框架-Combine響應(yīng)式框架、SwiftUI申明式UI框架、CodableJSON模型轉(zhuǎn)換

Result builder- 描述實(shí)現(xiàn)DSL的能力

動(dòng)態(tài)性- dynamicCallable、dynamicMemberLookup

其他- 擴(kuò)展、subscript、操作符重寫、嵌套類型、區(qū)間

Swift Package Manager- 基于Swift的包管理工具,可以直接用Xcode進(jìn)行管理更方便

struct- 初始化方法自動(dòng)補(bǔ)齊

類型推斷- 通過編譯器強(qiáng)大的類型推斷編寫代碼時(shí)可以減少很多類型申明

提示:類型推斷同時(shí)也會(huì)增加一定的編譯耗時(shí),不過Swift團(tuán)隊(duì)也在不斷的改善編譯速度。

安全性

代碼安全

let屬性- 使用let申明常量避免被修改。

值類型- 值類型可以避免在方法調(diào)用等參數(shù)傳遞過程中狀態(tài)被修改。

訪問控制- 通過public和final限制模塊外使用class不能被繼承和重寫。

強(qiáng)制異常處理- 方法需要拋出異常時(shí),需要申明為throw方法。當(dāng)調(diào)用可能會(huì)throw異常的方法,需要強(qiáng)制捕獲異常避免將異常暴露到上層。

模式匹配- 通過模式匹配檢測(cè)switch中未處理的case。

類型安全

強(qiáng)制類型轉(zhuǎn)換- 禁止隱式類型轉(zhuǎn)換避免轉(zhuǎn)換中帶來的異常問題。同時(shí)類型轉(zhuǎn)換不會(huì)帶來額外的運(yùn)行時(shí)消耗。

提示:編寫ObjC代碼時(shí),我們通常會(huì)在編碼時(shí)添加類型檢查避免運(yùn)行時(shí)崩潰導(dǎo)致Crash。

KeyPath - KeyPath相比使用字符串可以提供屬性名和類型信息,可以利用編譯器檢查。

泛型- 提供泛型和協(xié)議關(guān)聯(lián)類型,可以編寫出類型安全的代碼。相比Any可以更多利用編譯時(shí)檢查發(fā)現(xiàn)類型問題。

Enum關(guān)聯(lián)類型- 通過給特定枚舉指定類型避免使用Any。

內(nèi)存安全

空安全- 通過標(biāo)識(shí)可選值避免空指針帶來的異常問題

ARC- 使用自動(dòng)內(nèi)存管理避免手動(dòng)管理內(nèi)存帶來的各種內(nèi)存問題

強(qiáng)制初始化- 變量使用前必須初始化

內(nèi)存獨(dú)占訪問- 通過編譯器檢查發(fā)現(xiàn)潛在的內(nèi)存沖突問題

線程安全

值類型- 更多使用值類型減少在多線程中遇到的數(shù)據(jù)競(jìng)爭(zhēng)問題

async/await - 提供async函數(shù)使我們可以用結(jié)構(gòu)化的方式編寫并發(fā)操作。避免基于閉包的異步方式帶來的內(nèi)存循環(huán)引用和無法拋出異常的問題

Actor- 提供Actor模型避免多線程開發(fā)中進(jìn)行數(shù)據(jù)共享時(shí)發(fā)生的數(shù)據(jù)競(jìng)爭(zhēng)問題,同時(shí)避免在使用鎖時(shí)帶來的死鎖等問題

快速

值類型- 相比class不需要額外的堆內(nèi)存分配/釋放和更少的內(nèi)存消耗

方法靜態(tài)派發(fā)- 方法調(diào)用支持靜態(tài)調(diào)用相比原有ObjC消息轉(zhuǎn)發(fā)調(diào)用性能更好

編譯器優(yōu)化- Swift的靜態(tài)性可以使編譯器做更多優(yōu)化。例如Tree Shaking相關(guān)優(yōu)化移除未使用的類型/方法等減少二進(jìn)制文件大小。使用靜態(tài)派發(fā)/方法內(nèi)聯(lián)優(yōu)化/泛型特化/寫時(shí)復(fù)制等優(yōu)化提高運(yùn)行時(shí)性能

提示:ObjC消息派發(fā)會(huì)導(dǎo)致編譯器無法進(jìn)行移除無用方法/類的優(yōu)化,編譯器并不知道是否可能被用到。

ARC優(yōu)化- 雖然和ObjC一樣都是使用ARC,Swift通過編譯器優(yōu)化,可以進(jìn)行更快的內(nèi)存回收和更少的內(nèi)存引用計(jì)數(shù)管理

提示:相比ObjC,Swift內(nèi)部不需要使用autorelease進(jìn)行管理。

三、代碼質(zhì)量指標(biāo)

2050cffc-f59c-11ed-90ce-dac502259ad0.png

以上是一些常見的代碼質(zhì)量指標(biāo)。我們的目標(biāo)是如何更好的使用Swift編寫出符合代碼質(zhì)量指標(biāo)要求的代碼。

提示:本文不涉及設(shè)計(jì)模式/架構(gòu),更多關(guān)注如何通過合理使用Swift特性做局部代碼段的重構(gòu)。

一些不錯(cuò)的實(shí)踐

利用編譯檢查

減少使用Any/AnyObject

因?yàn)锳ny/AnyObject缺少明確的類型信息,編譯器無法進(jìn)行類型檢查,會(huì)帶來一些問題:

編譯器無法檢查類型是否正確保證類型安全

代碼中大量的as?轉(zhuǎn)換

類型的缺失導(dǎo)致編譯器無法做一些潛在的編譯優(yōu)化

使用as?帶來的問題

當(dāng)使用Any/AnyObject時(shí)會(huì)頻繁使用as?進(jìn)行類型轉(zhuǎn)換。這好像沒什么問題因?yàn)槭褂胊s?并不會(huì)導(dǎo)致程序Crash。不過代碼錯(cuò)誤至少應(yīng)該分為兩類,一類是程序本身的錯(cuò)誤通常會(huì)引發(fā)Crash,另外一種是業(yè)務(wù)邏輯錯(cuò)誤。使用as?只是避免了程序錯(cuò)誤Crash,但是并不能防止業(yè)務(wù)邏輯錯(cuò)誤。

func do(data: Any?) {
    guard let string = data as? String else {
        return
    }
    // 
}


do(1)
do("")

以上面的例子為例,我們進(jìn)行了as?轉(zhuǎn)換,當(dāng)data為String時(shí)才會(huì)進(jìn)行處理。但是當(dāng)do方法內(nèi)String類型發(fā)生了改變函數(shù),使用方并不知道已變更沒有做相應(yīng)的適配,這時(shí)候就會(huì)造成業(yè)務(wù)邏輯的錯(cuò)誤。

提示:這類錯(cuò)誤通常更難發(fā)現(xiàn),這也是我們?cè)谝淮握鎸?shí)bug場(chǎng)景遇到的。

使用自定義類型代替Dictionary

代碼中大量Dictionary數(shù)據(jù)結(jié)構(gòu)會(huì)降低代碼可維護(hù)性,同時(shí)帶來潛在的bug:

key需要字符串硬編碼,編譯時(shí)無法檢查

value沒有類型限制。修改時(shí)類型無法限制,讀取時(shí)需要重復(fù)類型轉(zhuǎn)換和解包操作

無法利用空安全特性,指定某個(gè)屬性必須有值

提示:自定義類型還有個(gè)好處,例如JSON轉(zhuǎn)自定義類型時(shí)會(huì)進(jìn)行類型/nil/屬性名檢查,可以避免將錯(cuò)誤數(shù)據(jù)丟到下一層。

推薦


let dic: [String: Any]
let num = dic["value"] as? Int
dic["name"] = "name"

推薦


struct Data {
  let num: Int
  var name: String?
}
let num = data.num
data.name = "name"

適合使用Dictionary的場(chǎng)景

數(shù)據(jù)不使用- 數(shù)據(jù)并不讀取只是用來傳遞。

解耦- 1.組件間通信解耦使用HashMap傳遞參數(shù)進(jìn)行通信。2.跨技術(shù)棧邊界的場(chǎng)景,混合棧間通信/前后端通信使用HashMap/JSON進(jìn)行通信。

使用枚舉關(guān)聯(lián)值代替Any

例如使用枚舉改造NSAttributedStringAPI,原有APIvalue為Any類型無法限制特定的類型。

優(yōu)化前

let string = NSMutableAttributedString()
string.addAttribute(.foregroundColor, value: UIColor.red, range: range)
改造后
enum NSAttributedStringKey {
  case foregroundColor(UIColor)
}
let string = NSMutableAttributedString()
string.addAttribute(.foregroundColor(UIColor.red), range: range) // 不傳遞Color會(huì)報(bào)錯(cuò)

使用泛型/協(xié)議關(guān)聯(lián)類型代替Any

使用泛型或協(xié)議關(guān)聯(lián)類型代替Any,通過泛型類型約束來使編譯器進(jìn)行更多的類型檢查。

使用枚舉/常量代替硬編碼

代碼中存在重復(fù)的硬編碼字符串/數(shù)字,在修改時(shí)可能會(huì)因?yàn)椴煌揭l(fā)bug。盡可能減少硬編碼字符串/數(shù)字,使用枚舉或常量代替。

使用KeyPath代替字符串硬編碼

KeyPath包含屬性名和類型信息,可以避免硬編碼字符串,同時(shí)當(dāng)屬性名或類型改變時(shí)編譯器會(huì)進(jìn)行檢查。

不推薦


class SomeClass: NSObject {
    @objc dynamic var someProperty: Int
    init(someProperty: Int) {
        self.someProperty = someProperty
    }
}
let object = SomeClass(someProperty: 10)
object.observeValue(forKeyPath: "", of: nil, change: nil, context: nil)

推薦


let object = SomeClass(someProperty: 10)
object.observe(.someProperty) { object, change in
}

內(nèi)存安全

減少使用!屬性

!屬性會(huì)在讀取時(shí)隱式強(qiáng)解包,當(dāng)值不存在時(shí)產(chǎn)生運(yùn)行時(shí)異常導(dǎo)致Crash。


class ViewController: UIViewController {
    @IBOutlet private var label: UILabel! // @IBOutlet需要使用!
}

減少使用!進(jìn)行強(qiáng)解包

使用!強(qiáng)解包會(huì)在值不存在時(shí)產(chǎn)生運(yùn)行時(shí)異常導(dǎo)致Crash。


var num: Int?
let num2 = num! // 錯(cuò)誤

提示:建議只在小范圍的局部代碼段使用!強(qiáng)解包。

避免使用try!進(jìn)行錯(cuò)誤處理

使用try!會(huì)在方法拋出異常時(shí)產(chǎn)生運(yùn)行時(shí)異常導(dǎo)致Crash。


try! method()

使用weak/unowned避免循環(huán)引用


resource.request().onComplete { [weak self] response in
  guard let self = self else {
    return
  }
  let model = self.updateModel(response)
  self.updateUI(model)
}


resource.request().onComplete { [unowned self] response in
  let model = self.updateModel(response)
  self.updateUI(model)
}

減少使用unowned

unowned在值不存在時(shí)會(huì)產(chǎn)生運(yùn)行時(shí)異常導(dǎo)致Crash,只有在確定self一定會(huì)存在時(shí)才使用unowned。


class Class {
    @objc unowned var object: Object
    @objc weak var object: Object?
}

unowned/weak區(qū)別:

weak - 必須設(shè)置為可選值,會(huì)進(jìn)行弱引用處理性能更差。會(huì)自動(dòng)設(shè)置為nil

unowned - 可以不設(shè)置為可選值,不會(huì)進(jìn)行弱引用處理性能更好。但是不會(huì)自動(dòng)設(shè)置為nil, 如果self已釋放會(huì)觸發(fā)錯(cuò)誤.

錯(cuò)誤處理方式

可選值- 調(diào)用方并不關(guān)注內(nèi)部可能會(huì)發(fā)生錯(cuò)誤,當(dāng)發(fā)生錯(cuò)誤時(shí)返回nil

try/catch- 明確提示調(diào)用方需要處理異常,需要實(shí)現(xiàn)Error協(xié)議定義明確的錯(cuò)誤類型

assert - 斷言。只能在Debug模式下生效

precondition- 和assert類似,可以再Debug/Release模式下生效

fatalError- 產(chǎn)生運(yùn)行時(shí)崩潰會(huì)導(dǎo)致Crash,應(yīng)避免使用

Result- 通常用于閉包異步回調(diào)返回值

減少使用可選值

可選值的價(jià)值在于通過明確標(biāo)識(shí)值可能會(huì)為nil并且編譯器強(qiáng)制對(duì)值進(jìn)行nil判斷。但是不應(yīng)該隨意的定義可選值,可選值不能用let定義,并且使用時(shí)必須進(jìn)行解包操作相對(duì)比較繁瑣。在代碼設(shè)計(jì)時(shí)應(yīng)考慮這個(gè)值是否有可能為nil,只在合適的場(chǎng)景使用可選值。

使用init注入代替可選值屬性

不推薦


class Object {
  var num: Int?
}
let object = Object()
object.num = 1

推薦


class Object {
  let num: Int


  init(num: Int) {
    self.num = num
  }
}
let object = Object(num: 1)

避免隨意給予可選值默認(rèn)值

在使用可選值時(shí),通常我們需要在可選值為nil時(shí)進(jìn)行異常處理。有時(shí)候我們會(huì)通過給予可選值默認(rèn)值的方式來處理。但是這里應(yīng)考慮在什么場(chǎng)景下可以給予默認(rèn)值。在不能給予默認(rèn)值的場(chǎng)景應(yīng)當(dāng)及時(shí)使用return或拋出異常,避免錯(cuò)誤的值被傳遞到更多的業(yè)務(wù)流程。

不推薦


func confirmOrder(id: String) {}
// 給予錯(cuò)誤的值會(huì)導(dǎo)致錯(cuò)誤的值被傳遞到更多的業(yè)務(wù)流程
confirmOrder(id: orderId ?? "")

推薦


func confirmOrder(id: String) {}


guard let orderId = orderId else {
    // 異常處理
    return
}
confirmOrder(id: orderId)

提示:通常強(qiáng)業(yè)務(wù)相關(guān)的值不能給予默認(rèn)值:例如商品/訂單id或是價(jià)格。在可以使用兜底邏輯的場(chǎng)景使用默認(rèn)值,例如默認(rèn)文字/文字顏色。

使用枚舉優(yōu)化可選值

Object結(jié)構(gòu)同時(shí)只會(huì)有一個(gè)值存在:

優(yōu)化前


class Object {
    var name: Int?
    var num: Int?
}

優(yōu)化后

降低內(nèi)存占用-枚舉關(guān)聯(lián)類型的大小取決于最大的關(guān)聯(lián)類型大小

邏輯更清晰- 使用enum相比大量使用if/else邏輯更清晰


enum CustomType {
    case name(String)
    case num(Int)
}

減少var屬性

使用計(jì)算屬性

使用計(jì)算屬性可以減少多個(gè)變量同步帶來的潛在bug。

不推薦


class model {
  var data: Object?
  var loaded: Bool
}
model.data = Object()
loaded = false

推薦


class model {
  var data: Object?
  var loaded: Bool {
    return data != nil
  }
}
model.data = Object()

提示:計(jì)算屬性因?yàn)槊看味紩?huì)重復(fù)計(jì)算,所以計(jì)算過程需要輕量避免帶來性能問題。

控制流

使用filter/reduce/map代替for循環(huán)

使用filter/reduce/map可以帶來很多好處,包括更少的局部變量,減少模板代碼,代碼更加清晰,可讀性更高。

不推薦


let nums = [1, 2, 3]
var result = []
for num in nums {
    if num < 3 {
        result.append(String(num))
    }
}
// result = ["1", "2"]

推薦


let nums = [1, 2, 3]
let result = nums.filter { $0 < 3 }.map { String($0) }
// result = ["1", "2"]

使用guard進(jìn)行提前返回

推薦


guard !a else {
    return
}
guard !b else {
    return
}
// do

不推薦


if a {
    if b {
        // do
    }
}

使用三元運(yùn)算符?:

推薦


let b = true
let a = b ? 1 : 2


let c: Int?
let b = c ?? 1

不推薦


var a: Int?
if b {
    a = 1
} else {
    a = 2
}

使用for where優(yōu)化循環(huán)

for循環(huán)添加where語句,只有當(dāng)where條件滿足時(shí)才會(huì)進(jìn)入循環(huán)

不推薦


for item in collection {
  if item.hasProperty {
    // ...
  }
}

推薦


for item in collection where item.hasProperty {
  // item.hasProperty == true,才會(huì)進(jìn)入循環(huán)
}

使用defer

defer可以保證在函數(shù)退出前一定會(huì)執(zhí)行??梢允褂胐efer中實(shí)現(xiàn)退出時(shí)一定會(huì)執(zhí)行的操作例如資源釋放等避免遺漏。


func method() {
    lock.lock()
    defer {
        lock.unlock()
        // 會(huì)在method作用域結(jié)束的時(shí)候調(diào)用
    }
    // do
}

字符串

使用"""

在定義復(fù)雜字符串時(shí),使用多行字符串字面量可以保持原有字符串的換行符號(hào)/引號(hào)等特殊字符,不需要使用進(jìn)行轉(zhuǎn)義。


let quotation = """
The White Rabbit put on his spectacles.  "Where shall I begin,
please your Majesty?" he asked.


"Begin at the beginning," the King said gravely, "and go on
till you come to the end; then stop."
"""

提示:上面字符串中的""和換行可以自動(dòng)保留。

使用字符串插值

使用字符串插值可以提高代碼可讀性。

不推薦


let multiplier = 3
let message = String(multiplier) + "times 2.5 is" + String((Double(multiplier) * 2.5))

推薦


let multiplier = 3
let message = "(multiplier) times 2.5 is (Double(multiplier) * 2.5)"

集合

使用標(biāo)準(zhǔn)庫提供的高階函數(shù)

不推薦


var nums = []
nums.count == 0
nums[0]

推薦


var nums = []
nums.isEmpty
nums.first

訪問控制

Swift中默認(rèn)訪問控制級(jí)別為internal。編碼中應(yīng)當(dāng)盡可能減小屬性/方法/類型的訪問控制級(jí)別隱藏內(nèi)部實(shí)現(xiàn)。

提示:同時(shí)也有利于編譯器進(jìn)行優(yōu)化。

使用private/fileprivate修飾私有屬性和方法


private let num = 1
class MyClass {
    private var num: Int
}

使用private(set)修飾外部只讀/內(nèi)部可讀寫屬性


class MyClass {
    private(set) var num = 1
}
let num = MyClass().num
MyClass().num = 2 // 會(huì)編譯報(bào)錯(cuò)

函數(shù)

使用參數(shù)默認(rèn)值

使用參數(shù)默認(rèn)值,可以使調(diào)用方傳遞更少的參數(shù)。

不推薦


func test(a: Int, b: String?, c: Int?) {
}
test(1, nil, nil)

推薦


func test(a: Int, b: String? = nil, c: Int? = nil) {
}
test(1)

提示:相比ObjC,參數(shù)默認(rèn)值也可以讓我們定義更少的方法。

限制參數(shù)數(shù)量

當(dāng)方法參數(shù)過多時(shí)考慮使用自定義類型代替。

不推薦


func f(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int) {
}

推薦


struct Params {
    let a, b, c, d, e, f: Int
}
func f(params: Params) {
}

使用@discardableResult

某些方法使用方并不一定會(huì)處理返回值,可以考慮添加@discardableResult標(biāo)識(shí)提示Xcode允許不處理返回值不進(jìn)行warning提示。


// 上報(bào)方法使用方不關(guān)心是否成功
func report(id: String) -> Bool {} 


@discardableResult func report2(id: String) -> Bool {}


report("1") // 編譯器會(huì)警告
report2("1") // 不處理返回值編譯器不會(huì)警告

元組

避免過長的元組

元組雖然具有類型信息,但是并不包含變量名信息,使用方并不清晰知道變量的含義。所以當(dāng)元組數(shù)量過多時(shí)考慮使用自定義類型代替。


func test() -> (Int, Int, Int) {


}


let (a, b, c) = test()
// a,b,c類型一致,沒有命名信息不清楚每個(gè)變量的含義

系統(tǒng)庫

KVO/Notification使用blockAPI

block API的優(yōu)勢(shì):

KVO可以支持KeyPath

不需要主動(dòng)移除監(jiān)聽,observer釋放時(shí)自動(dòng)移除監(jiān)聽

不推薦


class Object: NSObject {
  init() {
    super.init()
    addObserver(self, forKeyPath: "value", options: .new, context: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(test), name: NSNotification.Name(rawValue: ""), object: nil)
  }


  override class func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
  }


  @objc private func test() {
  }


  deinit {
    removeObserver(self, forKeyPath: "value")
    NotificationCenter.default.removeObserver(self)
  }


}

推薦


class Object: NSObject {


  private var observer: AnyObserver?
  private var kvoObserver: NSKeyValueObservation?


  init() {
    super.init()
    observer = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: ""), object: nil, queue: nil) { (_) in 
    }
    kvoObserver = foo.observe(.value, options: [.new]) { (foo, change) in
    }
  }
}

Protocol

使用protocol代替繼承

Swift中針對(duì)protocol提供了很多新特性,例如默認(rèn)實(shí)現(xiàn),關(guān)聯(lián)類型,支持值類型。在代碼設(shè)計(jì)時(shí)可以優(yōu)先考慮使用protocol來避免臃腫的父類同時(shí)更多使用值類型。

提示:一些無法用protocol替代繼承的場(chǎng)景:1.需要繼承NSObject子類。2.需要調(diào)用super方法。3.實(shí)現(xiàn)抽象類的能力。

Extension

使用extension組織代碼

使用extension將私有方法/父類方法/協(xié)議方法等不同功能代碼進(jìn)行分離更加清晰/易維護(hù)。


class MyViewController: UIViewController {
  // class stuff here
}
// MARK: - Private
extension: MyViewController {
    private func method() {}
}
// MARK: - UITableViewDataSource
extension MyViewController: UITableViewDataSource {
  // table view data source methods
}
// MARK: - UIScrollViewDelegate
extension MyViewController: UIScrollViewDelegate {
  // scroll view delegate methods
}

代碼風(fēng)格

良好的代碼風(fēng)格可以提高代碼的可讀性,統(tǒng)一的代碼風(fēng)格可以降低團(tuán)隊(duì)內(nèi)相互理解成本。對(duì)于Swift的代碼格式化建議使用自動(dòng)格式化工具實(shí)現(xiàn),將自動(dòng)格式化添加到代碼提交流程,通過定義Lint規(guī)則統(tǒng)一團(tuán)隊(duì)內(nèi)代碼風(fēng)格??紤]使用SwiftFormat和SwiftLint。

提示:SwiftFormat主要關(guān)注代碼樣式的格式化,SwiftLint可以使用autocorrect自動(dòng)修復(fù)部分不規(guī)范的代碼。

常見的自動(dòng)格式化修正

移除多余的;

最多只保留一行換行

自動(dòng)對(duì)齊空格

限制每行的寬度自動(dòng)換行

性能優(yōu)化

性能優(yōu)化上主要關(guān)注提高運(yùn)行時(shí)性能和降低二進(jìn)制體積。需要考慮如何更好的使用Swift特性,同時(shí)提供更多信息給編譯器進(jìn)行優(yōu)化。

使用Whole Module Optimization

當(dāng)Xcode開啟WMO優(yōu)化時(shí),編譯器可以將整個(gè)程序編譯為一個(gè)文件進(jìn)行更多的優(yōu)化。例如通過推斷final/函數(shù)內(nèi)聯(lián)/泛型特化更多使用靜態(tài)派發(fā),并且可以移除部分未使用的代碼。

使用源代碼打包

當(dāng)我們使用組件化時(shí),為了提高編譯速度和打包效率,通常單個(gè)組件獨(dú)立編譯生成靜態(tài)庫,最后多個(gè)組件直接使用靜態(tài)庫進(jìn)行打包。這種場(chǎng)景下WMO僅針對(duì)internal以內(nèi)作用域生效,對(duì)于public/open缺少外部使用信息所以無法進(jìn)行優(yōu)化。所以對(duì)于大量使用Swift的項(xiàng)目,使用全量代碼打包更有利于編譯器做更多優(yōu)化。

減少方法動(dòng)態(tài)派發(fā)

使用final-class/方法/屬性申明為final,編譯器可以優(yōu)化為靜態(tài)派發(fā)

使用private-方法/屬性申明為private,編譯器可以優(yōu)化為靜態(tài)派發(fā)

避免使用dynamic-dynamic會(huì)使方法通過ObjC消息轉(zhuǎn)發(fā)的方式派發(fā)

使用WMO- 編譯器可以自動(dòng)分析推斷出final優(yōu)化為靜態(tài)派發(fā)

使用Slice共享內(nèi)存優(yōu)化性能

在使用Array/String時(shí),可以使用Slice切片獲取一部分?jǐn)?shù)據(jù)。Slice保存對(duì)原始Array/String的引用共享內(nèi)存數(shù)據(jù),不需要重新分配空間進(jìn)行存儲(chǔ)。


let midpoint = absences.count / 2


let firstHalf = absences[..

提示:應(yīng)避免一直持有Slice,Slice會(huì)延長原始Array/String的生命周期導(dǎo)致無法被釋放造成內(nèi)存泄漏。

protocol添加AnyObject


protocol AnyProtocol {}


protocol ObjectProtocol: AnyObject {}

當(dāng)protocol僅限制為class使用時(shí),繼承AnyObject協(xié)議可以使編譯器不需要考慮值類型實(shí)現(xiàn),提高運(yùn)行時(shí)性能。

使用@inlinable進(jìn)行方法內(nèi)聯(lián)優(yōu)化


// 原始代碼
let label = UILabel().then {
    $0.textAlignment = .center
    $0.textColor = UIColor.black
    $0.text = "Hello, World!"
}

以then庫為例,他使用閉包進(jìn)行對(duì)象初始化以后的相關(guān)設(shè)置。但是 then 方法以及閉包也會(huì)帶來額外的性能消耗。

內(nèi)聯(lián)優(yōu)化


@inlinable
public func then(_ block: (Self) throws -> Void) rethrows -> Self {
    try block(self)
    return self
}


// 編譯器內(nèi)聯(lián)優(yōu)化后
let label = UILabel() 
label.textAlignment = .center
label.textColor = UIColor.black
label.text = "Hello, World!"

屬性

使用lazy延時(shí)初始化屬性


class View {
    var lazy label: UILabel = {
        let label = UILabel()
        self.addSubView(label)
        return label
    }()
}

lazy屬性初始化會(huì)延遲到第一次使用時(shí),常見的使用場(chǎng)景:

初始化比較耗時(shí)

可能不會(huì)被使用到

初始化過程需要使用self

提示:lazy屬性不能保證線程安全

避免使用private let屬性

private let屬性會(huì)增加每個(gè)class對(duì)象的內(nèi)存大小。同時(shí)會(huì)增加包大小,因?yàn)樾枰獮閷傩陨上嚓P(guān)的信息。可以考慮使用文件級(jí)private let申明或static常量代替。

不推薦


class Object {
    private let title = "12345"
}

推薦


private let title = "12345"
class Object {
    static let title = ""
}

提示:這里并不包括通過init初始化注入的屬性。

使用didSet/willSet時(shí)進(jìn)行Diff

某些場(chǎng)景需要使用didSet/willSet屬性檢查器監(jiān)控屬性變化,做一些額外的計(jì)算。但是由于didSet/willSet并不會(huì)檢查新/舊值是否相同,可以考慮添加新/舊值判斷,只有當(dāng)值真的改變時(shí)才進(jìn)行運(yùn)算提高性能。

優(yōu)化前


class Object {
    var orderId: String? {
        didSet {
            // 拉取接口等操作
        }
    }
}

例如上面的例子,當(dāng)每一次orderId變更時(shí)需要重新拉取當(dāng)前訂單的數(shù)據(jù),但是當(dāng)orderId值一樣時(shí),拉取訂單數(shù)據(jù)是無效執(zhí)行。

優(yōu)化后


class Object {
    var orderId: String? {
        didSet {
            // 判斷新舊值是否相等
            guard oldValue != orderId else {
                return
            }
            // 拉取接口等操作
        }
    }
}

集合

集合使用lazy延遲序列

var nums = [1, 2, 3]
var result = nums.lazy.map { String($0) }
result[0] // 對(duì)1進(jìn)行map操作
result[1] // 對(duì)2進(jìn)行map操作

在集合操作時(shí)使用lazy,可以將數(shù)組運(yùn)算操作推遲到第一次使用時(shí),避免一次性全部計(jì)算。

提示:例如長列表,我們需要?jiǎng)?chuàng)建每個(gè)cell對(duì)應(yīng)的視圖模型,一次性創(chuàng)建太耗費(fèi)時(shí)間。



?

使用合適的集合方法優(yōu)化性能

不推薦


var items = [1, 2, 3]
items.filter({ $0 > 1 }).first // 查找出所有大于1的元素,之后找出第一個(gè)

推薦


var items = [1, 2, 3]
items.first(where: { $0 > 1 }) // 查找出第一個(gè)大于1的元素直接返回

使用值類型

Swift中的值類型主要是結(jié)構(gòu)體/枚舉/元組。

啟動(dòng)性能- APP啟動(dòng)時(shí)值類型沒有額外的消耗,class有一定額外的消耗。

運(yùn)行時(shí)性能- 值類型不需要在堆上分配空間/額外的引用計(jì)數(shù)管理。更少的內(nèi)存占用和更快的性能。

包大小- 相比class,值類型不需要?jiǎng)?chuàng)建ObjC類對(duì)應(yīng)的ro_data_t數(shù)據(jù)結(jié)構(gòu)。

提示:class即使沒有繼承NSObject也會(huì)生成ro_data_t,里面包含了ivars屬性信息。如果屬性/方法申明為@objc還會(huì)生成對(duì)應(yīng)的方法列表。

提示:struct無法代替class的一些場(chǎng)景:1.需要使用繼承調(diào)用super。2.需要使用引用類型。3.需要使用deinit。4.需要在運(yùn)行時(shí)動(dòng)態(tài)轉(zhuǎn)換一個(gè)實(shí)例的類型。

提示:不是所有struct都會(huì)保存在棧上,部分?jǐn)?shù)據(jù)大的struct也會(huì)保存在堆上。

集合元素使用值類型

集合元素使用值類型。因?yàn)镹SArray并不支持值類型,編譯器不需要處理可能需要橋接到NSArray的場(chǎng)景,可以移除部分消耗。

純靜態(tài)類型避免使用class

當(dāng)class只包含靜態(tài)方法/屬性時(shí),考慮使用enum代替class,因?yàn)閏lass會(huì)生成更多的二進(jìn)制代碼。

不推薦


class Object {
    static var num: Int
    static func test() {}
}

推薦


enum Object {
    static var num: Int
    static func test() {}
}

提示:為什么用enum而不是struct,因?yàn)閟truct會(huì)額外生成init方法。

值類型性能優(yōu)化

考慮使用引用類型

值類型為了維持值語義,會(huì)在每次賦值/參數(shù)傳遞/修改時(shí)進(jìn)行復(fù)制。雖然編譯器本身會(huì)做一些優(yōu)化,例如寫時(shí)復(fù)制優(yōu)化,在修改時(shí)減少復(fù)制頻率,但是這僅針對(duì)于標(biāo)準(zhǔn)庫提供的集合和String結(jié)構(gòu)有效,對(duì)于自定義結(jié)構(gòu)需要自己實(shí)現(xiàn)。對(duì)于參數(shù)傳遞編譯器在一些場(chǎng)景會(huì)優(yōu)化為直接傳遞引用的方式避免復(fù)制行為。

但是對(duì)于一些數(shù)據(jù)特別大的結(jié)構(gòu),同時(shí)需要頻繁變更修改時(shí)也可以考慮使用引用類型實(shí)現(xiàn)。

使用inout傳遞參數(shù)減少復(fù)制

雖然編譯器本身會(huì)進(jìn)行寫時(shí)復(fù)制的優(yōu)化,但是部分場(chǎng)景編譯器無法處理。

不推薦


func append_one(_ a: [Int]) -> [Int] {
  var a = a
  a.append(1) // 無法被編譯器優(yōu)化,因?yàn)檫@時(shí)候有2個(gè)引用持有數(shù)組
  return a
}


var a = [1, 2, 3]
a = append_one(a)

推薦

直接使用inout傳遞參數(shù)


func append_one_in_place(a: inout [Int]) {
  a.append(1)
}


var a = [1, 2, 3]
append_one_in_place(&a)

使用isKnownUniquelyReferenced實(shí)現(xiàn)寫時(shí)復(fù)制

默認(rèn)情況下結(jié)構(gòu)體中包含引用類型,在修改時(shí)只會(huì)重新拷貝引用。但是我們希望CustomData具備值類型的特性,所以當(dāng)修改時(shí)需要重新復(fù)制NSMutableData避免復(fù)用。但是復(fù)制操作本身是耗時(shí)操作,我們希望可以減少一些不必要的復(fù)制。

優(yōu)化前


struct CustomData {
    fileprivate var _data: NSMutableData
    var _dataForWriting: NSMutableData {
        mutating get {
            _data = _data.mutableCopy() as! NSMutableData
            return _data
        }
    }
    init(_ data: NSData) {
        self._data = data.mutableCopy() as! NSMutableData
    }


    mutating func append(_ other: MyData) {
        _dataForWriting.append(other._data as Data)
    }
}


var buffer = CustomData(NSData())
for _ in 0..<5 {
    buffer.append(x) // 每一次調(diào)用都會(huì)復(fù)制
}

優(yōu)化后

使用isKnownUniquelyReferenced檢查如果是唯一引用不進(jìn)行復(fù)制。


final class Box {
    var unbox: A
    init(_ value: A) { self.unbox = value }
}


struct CustomData {
    fileprivate var _data: Box
    var _dataForWriting: NSMutableData {
        mutating get {
            // 檢查引用是否唯一
            if !isKnownUniquelyReferenced(&_data) {
                _data = Box(_data.unbox.mutableCopy() as! NSMutableData)
            }
            return _data.unbox
        }
    }
    init(_ data: NSData) {
        self._data = Box(data.mutableCopy() as! NSMutableData)
    }
}


var buffer = CustomData(NSData())
for _ in 0..<5 {
    buffer.append(x) // 只會(huì)在第一次調(diào)用時(shí)進(jìn)行復(fù)制
}

提示:對(duì)于ObjC類型isKnownUniquelyReferenced會(huì)直接返回false。

減少使用Objc特性

避免使用Objc類型

盡可能避免在Swift中使用NSString/NSArray/NSDictionary等ObjC基礎(chǔ)類型。以Dictionary為例,雖然Swift Runtime可以在NSArray和Array之間進(jìn)行隱式橋接需要O(1)的時(shí)間。但是字典當(dāng)Key和Value既不是類也不是@objc協(xié)議時(shí),需要對(duì)每個(gè)值進(jìn)行橋接,可能會(huì)導(dǎo)致消耗O(n)時(shí)間。

減少添加@objc標(biāo)識(shí)

@objc標(biāo)識(shí)雖然不會(huì)強(qiáng)制使用消息轉(zhuǎn)發(fā)的方式來調(diào)用方法/屬性,但是他會(huì)默認(rèn)ObjC是可見的會(huì)生成和ObjC一樣的ro_data_t結(jié)構(gòu)。

避免使用@objcMembers

使用@objcMembers修飾的類,默認(rèn)會(huì)為類/屬性/方法/擴(kuò)展都加上@objc標(biāo)識(shí)。


@objcMembers class Object: NSObject {
}

提示:你也可以使用@nonobjc取消支持ObjC。

避免繼承NSObject

你只需要在需要使用NSObject特性時(shí)才需要繼承,例如需要實(shí)現(xiàn)UITableViewDataSource相關(guān)協(xié)議。

使用let變量/屬性

優(yōu)化集合創(chuàng)建

集合不需要修改時(shí),使用let修飾,編譯器會(huì)優(yōu)化創(chuàng)建集合的性能。例如針對(duì)let集合,編譯器在創(chuàng)建時(shí)可以分配更小的內(nèi)存大小。

優(yōu)化逃逸閉包

在Swift中,當(dāng)捕獲var變量時(shí)編譯器需要生成一個(gè)在堆上的Box保存變量用于之后對(duì)于變量的讀/寫,同時(shí)需要額外的內(nèi)存管理操作。如果是let變量,編譯器可以保存值復(fù)制或引用,避免使用Box。

避免使用大型struct使用class代替

大型struct通常是指屬性特別多并且嵌套類型很多。目前swift編譯器針對(duì)struct等值類型編譯優(yōu)化處理的并不好,會(huì)生成大量的assignWithCopy、assignWithCopy等copy相關(guān)方法,生成大量的二進(jìn)制代碼。使用class類型可以避免生成相關(guān)的copy方法。

提示:不要小看這部分二進(jìn)制的影響,個(gè)人在日常項(xiàng)目中遇到過復(fù)雜的大型struct能生成幾百KB的二進(jìn)制代碼。但是目前并沒有好的方法去發(fā)現(xiàn)這類struct去做優(yōu)化,只能通過相關(guān)工具去查看生成的二進(jìn)制詳細(xì)信息。希望官方可以早點(diǎn)優(yōu)化。

優(yōu)先使用Encodable/Decodable協(xié)議代替Codable

因?yàn)閷?shí)現(xiàn)Encodable和Decodable協(xié)議的結(jié)構(gòu),編譯器在編譯時(shí)會(huì)自動(dòng)生成對(duì)應(yīng)的init(from decoder: Decoder)和encode(to: Encoder)方法。Codable同時(shí)實(shí)現(xiàn)了Encodable和Decodable協(xié)議,但是大部分場(chǎng)景下我們只需要encode或decode能力,所以明確指定實(shí)現(xiàn)Encodable或Decodable協(xié)議可以減少生成對(duì)應(yīng)的方法減少包體積。

提示:對(duì)于屬性比較多的類型結(jié)構(gòu)會(huì)產(chǎn)生很大的二進(jìn)制代碼,有興趣可以用相關(guān)的工具看看生成的二進(jìn)制文件。

減少使用Equatable協(xié)議

因?yàn)閷?shí)現(xiàn)Equatable協(xié)議的結(jié)構(gòu),編譯器在編譯時(shí)會(huì)自動(dòng)生成對(duì)應(yīng)的equal方法。默認(rèn)實(shí)現(xiàn)是針對(duì)所有字段進(jìn)行比較會(huì)生成大量的代碼。所以當(dāng)我們不需要實(shí)現(xiàn)==比較能力時(shí)不要實(shí)現(xiàn)Equatable或者對(duì)于屬性特別多的類型也可以考慮重寫Equatable協(xié)議,只針對(duì)部分屬性進(jìn)行比較,這樣可以生成更少的代碼減少包體積。

提示:對(duì)于屬性特別多的類型也可以考慮重寫Equatable協(xié)議,只針對(duì)部分屬性進(jìn)行比較,同時(shí)也可以提升性能。

四、總結(jié)

個(gè)人從Swift3.0開始將Swift作為第一語言使用。編寫Swift代碼并不只是簡(jiǎn)單對(duì)于ObjC代碼的翻譯/重寫,需要對(duì)于Swift特性更多的理解才能更好的利用這些特性帶來更多的收益。同時(shí)我們需要關(guān)注每個(gè)版本Swift的優(yōu)化/改進(jìn)和新特性。在這過程中也會(huì)提高我們的編碼能力,加深對(duì)于一些通用編程概念/思想的理解,包括空安全、值類型、協(xié)程、不共享數(shù)據(jù)的Actor并發(fā)模型、函數(shù)式編程、面向協(xié)議編程、內(nèi)存所有權(quán)等。對(duì)于新的現(xiàn)代編程語言例如Swift/Dart/TS/Kotlin/Rust等,很多特性/思想都是相互借鑒,當(dāng)我們理解這些概念/思想以后對(duì)于理解其他語言也會(huì)更容易。






審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • DSL
    DSL
    +關(guān)注

    關(guān)注

    2

    文章

    58

    瀏覽量

    38310
  • SWIFT
    +關(guān)注

    關(guān)注

    0

    文章

    116

    瀏覽量

    23804
  • ARC
    ARC
    +關(guān)注

    關(guān)注

    0

    文章

    42

    瀏覽量

    16473
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1634

    瀏覽量

    49136

原文標(biāo)題:萬字長文詳解如何使用 Swift 提高代碼質(zhì)量

文章出處:【微信號(hào):OSC開源社區(qū),微信公眾號(hào):OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    TPSM843620 SWIFT?降壓評(píng)估模塊

    電子發(fā)燒友網(wǎng)站提供《TPSM843620 SWIFT?降壓評(píng)估模塊.pdf》資料免費(fèi)下載
    發(fā)表于 12-05 14:05 ?0次下載
    TPSM843620 <b class='flag-5'>SWIFT</b>?降壓評(píng)估模塊

    TPS542A50 SWIFT?降壓轉(zhuǎn)換器評(píng)估模塊用戶指南

    電子發(fā)燒友網(wǎng)站提供《TPS542A50 SWIFT?降壓轉(zhuǎn)換器評(píng)估模塊用戶指南.pdf》資料免費(fèi)下載
    發(fā)表于 12-04 16:25 ?0次下載
    TPS542A50 <b class='flag-5'>SWIFT</b>?降壓轉(zhuǎn)換器評(píng)估模塊用戶指南

    怎么樣提高verilog代碼編寫水平?

    ? A:以下是一些提高 Verilog 代碼編寫水平的自學(xué)方法: 深入學(xué)習(xí)基礎(chǔ)知識(shí):重新鞏固數(shù)字電路的基本概念,如邏輯門、組合邏輯、時(shí)序邏輯、狀態(tài)機(jī)等,這是編寫高質(zhì)量 Verilog 代碼
    發(fā)表于 09-25 20:05

    Swift 6.0引領(lǐng)編程語言新趨勢(shì)

    近日,蘋果公司公布了一系列重磅消息:推出iOS/iPadOS 18和macOS 15 Sequoia等操作系統(tǒng)更新,以及Swift編程語言的全新版本——Swift 6.0。此番升級(jí)重點(diǎn)關(guān)注編程安全性、并發(fā)處理能力的提升,并大幅擴(kuò)展了Sw
    的頭像 發(fā)表于 09-20 15:57 ?349次閱讀

    如何正確提高電能質(zhì)量

    電能質(zhì)量不僅關(guān)系到電力系統(tǒng)本身的穩(wěn)定運(yùn)行,更影響到廣大用戶的日常生活和產(chǎn)業(yè)發(fā)展。因此,采取有效措施提高電能質(zhì)量,是確保電力供應(yīng)安全、可靠且高效的重要環(huán)節(jié)。下面,我們將詳細(xì)探討幾種提高
    的頭像 發(fā)表于 08-30 10:11 ?425次閱讀

    蘋果推出全新開源Swift軟件包

    七月三十一日,蘋果企業(yè)總部對(duì)外正式發(fā)表公告,宣布昨日(即七月二十九日)成功推出全新的開源 Swift 軟件包—— (喚名為 swift-homomorphic-encryption)。此舉旨在為 Swift 編程語言帶來應(yīng)用便利
    的頭像 發(fā)表于 07-31 15:17 ?392次閱讀

    DevOps中的質(zhì)量門工作原理,以及靜態(tài)代碼分析Klocwork和Perforce Helix QAC在質(zhì)量門中的實(shí)踐應(yīng)用

    質(zhì)量門”正如其名:它們?cè)谲浖_發(fā)生命周期(SDLC)的各個(gè)階段充當(dāng)質(zhì)量里程碑(或 "門檻"),防止不良代碼通過,從而確保交付高質(zhì)量的軟件。 閱讀本文,您將了解什么是
    的頭像 發(fā)表于 07-29 15:12 ?406次閱讀

    什么是質(zhì)量閘門?

    無論您是執(zhí)行增量分析、差異分析還是集成分析,靜態(tài)分析/SAST 工具都旨在優(yōu)化 DevOps 和 DevSecOps 流程,并且可以作為檢查代碼質(zhì)量和安全問題的一種質(zhì)量閘門類型 —— 而不會(huì)放慢開發(fā)
    的頭像 發(fā)表于 07-16 23:11 ?244次閱讀
    什么是<b class='flag-5'>質(zhì)量</b>閘門?

    該如何提高代碼容錯(cuò)率、降低代碼耦合度?

    提高RT-Thread代碼的容錯(cuò)率和降低耦合度是確保代碼質(zhì)量和可維護(hù)性的關(guān)鍵,下面列舉了幾種在編寫代碼時(shí),
    的頭像 發(fā)表于 06-26 08:10 ?676次閱讀
    該如何<b class='flag-5'>提高</b><b class='flag-5'>代碼</b>容錯(cuò)率、降低<b class='flag-5'>代碼</b>耦合度?

    上位機(jī)監(jiān)控軟件如何提高質(zhì)量

    。本文將從以下幾個(gè)方面詳細(xì)探討如何提高上位機(jī)監(jiān)控軟件的質(zhì)量: 需求分析與設(shè)計(jì) 軟件架構(gòu)與模塊化 編程規(guī)范與代碼質(zhì)量 數(shù)據(jù)采集與處理 用戶界面設(shè)計(jì) 系統(tǒng)性能與穩(wěn)定性 安全性 可維護(hù)性與可
    的頭像 發(fā)表于 06-07 09:14 ?382次閱讀

    探討AI編寫代碼技術(shù),以及提高代碼質(zhì)量的關(guān)鍵:靜態(tài)代碼分析工具Perforce Helix QAC &amp; Klocwork

    令軟件開發(fā)人員夜不能寐的事情比比皆是。如今,他們最關(guān)心的問題不再是如何用自己喜歡的語言(C、C++、Erlang、Java 等)表達(dá)最新的算法,而是人工智能(AI)。 本文中,我們將介紹AI編寫代碼
    的頭像 發(fā)表于 06-05 14:10 ?406次閱讀

    宏碁發(fā)布首款搭載Copilot+的Swift 14 AI筆記本電腦

    Swift 14 AI擁有多款不同配置,均配備Snapdragon X Elite或Snapdragon X Plus平臺(tái),搭載高效能NPU,實(shí)現(xiàn)終端側(cè)AI功能。其先進(jìn)的計(jì)算機(jī)智能功能可以快速完成復(fù)雜任務(wù),極大地提高效率。
    的頭像 發(fā)表于 05-22 09:55 ?513次閱讀

    如何提升代碼質(zhì)量與效率的秘訣

    提高編程能力其實(shí)沒有捷徑,最佳方式就是多寫代碼。 不過,除了寫大量代碼,提升編程能力還需要大量閱讀別人寫的代碼。
    的頭像 發(fā)表于 04-28 14:53 ?402次閱讀
    如何提升<b class='flag-5'>代碼</b><b class='flag-5'>質(zhì)量</b>與效率的秘訣

    代碼開發(fā)平臺(tái)的崛起:優(yōu)勢(shì)、特點(diǎn)與應(yīng)用

    代碼開發(fā)平臺(tái)是近年來迅速崛起的一種創(chuàng)新型軟件開發(fā)工具,以其高效、靈活的開發(fā)模式正顛覆著傳統(tǒng)的開發(fā)方式。不再需要編寫大量繁雜的代碼,開發(fā)者們可以在圖形化界面中以拖拽、配置的方式進(jìn)行應(yīng)用的搭建,大大提高開發(fā)效率和
    的頭像 發(fā)表于 04-18 10:43 ?376次閱讀
    低<b class='flag-5'>代碼</b>開發(fā)平臺(tái)的崛起:優(yōu)勢(shì)、特點(diǎn)與應(yīng)用

    電容器提高電能質(zhì)量的方法

    電容器提高電能質(zhì)量的方法 電容器是一種電子元件,主要功能是儲(chǔ)存電荷并釋放出來。在電能傳輸、電路穩(wěn)定性以及電力系統(tǒng)調(diào)節(jié)等方面起到重要的作用。為了提高電容器的電能質(zhì)量,可以從以下幾個(gè)方面入
    的頭像 發(fā)表于 01-17 11:36 ?1099次閱讀
    主站蜘蛛池模板: 精品久久久无码21P发布| 芳草地社区在线视频| 成 人 色综合| 久久内在线视频精品mp4| 小SB几天没做SAO死了H| 闺蜜撬开我的腿用黄瓜折磨我| 免费人成在线观看视频不卡| 制服丝袜 快播| 久久国产精品萌白酱免费| 一个人在线观看的视频| 久草高清在线| 伊人22222| 久久99精品涩AV毛片观看| 伊人热人久久中文字幕| 久久欧洲视频| 2018年免费三级av观看| 真实的强视频免费网站| 久久久大香菇| 2019久久视频这里有精品15| 乱子伦在线观看中文字幕| 97无码欧美熟妇人妻蜜桃天美| 美女搞鸡网站| www.色小姐| 使劲别停好大好深好爽动态图| 国产浮力草草影院CCYY| 亚洲国产精品综合久久一线| 九九大香尹人视频免费| 69夫妻交友网| 日韩男明星| 国产一区2区| 在线观看a视频| 欧美久久综合网| 国产精品久久人妻无码网站一区L| 亚洲AV午夜福利精品香蕉麻豆| 久久er99热精品一区二区| 9277高清在线观看视频| 日韩在线中文字幕无码| 好男人的视频在线观看| 91精选国产| 偷偷鲁青春草原视频分类| 精品香蕉99久久久久网站|