一. 背景
1.1 Swift 發(fā)展歷史
2010 年 7 月鲸阻,克里斯(Chris Lattner)開始設(shè)計 Swift顽分。完成基礎(chǔ)架構(gòu)后隆敢,克里斯帶領(lǐng)開發(fā)小組陸續(xù)完成語法設(shè)計裁蚁、編譯器粱胜、運(yùn)行時爽撒、框架挪哄、IDE 和文檔等相關(guān)工作私沮。
WWDC 2014趾断,經(jīng)歷四年的開發(fā)拒名,Swift 發(fā)布。
WWDC 2015芋酌,Swift 2.0增显,蘋果宣布 Swift 開源,包含編譯器和標(biāo)準(zhǔn)庫脐帝。這一階段發(fā)展迅速同云,變動也非常頻繁。因此開發(fā)者也都處于嘗試或觀望狀態(tài)堵腹。
2016 Swift 3.0炸站,是語法和接口變化最大的一個版本,大量直接從 OC 移植過來的方法名被簡化了疚顷,大量常用 Foundation 的類在 Swift 中改成了去掉 "NS" 前綴的結(jié)構(gòu)體和類旱易,原來 OC 方法名的很多描述性語句變成了 label禁偎,一些開發(fā)框架中的 C 語法 API(如 GCD、CoreGraphics等)也統(tǒng)一了風(fēng)格阀坏, Swift 語法風(fēng)格基本定型如暖。
2019 Swift 5.0,ABI 穩(wěn)定忌堂,并且向后兼容盒至。2019 年 3 月,Swift 5.0 正式發(fā)布士修。目前枷遂,Swift 的當(dāng)前版本包含跨 Apple 平臺的應(yīng)用程序二進(jìn)制接口(ABI)的穩(wěn)定版本。這是朝著幫助開發(fā)人員在專用操作系統(tǒng)(如 iOS棋嘲,macOS酒唉,tvOS,watchOS 和 iPadOS)上使用Swift邁出的一大步沸移。蘋果正在構(gòu)建一個堅實的生態(tài)系統(tǒng)黔州,因為現(xiàn)在標(biāo)準(zhǔn)的 Swift 庫已包含在 OS 版本中。
1.2 ABI 穩(wěn)定
ABI(Application Binary Interface)阔籽,即應(yīng)用程序二進(jìn)制接口,描述了應(yīng)用程序和操作系統(tǒng)之間牲蜀,一個應(yīng)用和它的庫之間的接口笆制。在 iOS 和 macOS 平臺,Swift 編寫的二進(jìn)制程序在運(yùn)行時通過 ABI 與其他程序庫或組件進(jìn)行交互涣达。程序的編譯會產(chǎn)生一個或者多個二進(jìn)制實體在辆,這些二進(jìn)制實體必須在一些很底層的細(xì)節(jié)上達(dá)成一致,才能被鏈接在一起執(zhí)行度苔〈衣ǎ可以說ABI就是一個規(guī)范,一種協(xié)議寇窑。它會規(guī)定如何調(diào)用函數(shù)鸦概,如何在內(nèi)存中表示數(shù)據(jù),甚至是如何存儲和訪問 metadata甩骏。Xcode 10.2 集成了 Swift 5.0 編譯器窗市,只要使用這個版本以上的編譯器,編譯出來的二進(jìn)制就是 ABI 穩(wěn)定的饮笛。
在此示例中咨察,使用 Swift 5.0 構(gòu)建的應(yīng)用程序?qū)⒃诎惭b了 Swift 5 標(biāo)準(zhǔn)庫的系統(tǒng)以及 Swift 5.1 或?qū)淼?Swift 6 的系統(tǒng)上運(yùn)行。
ABI 穩(wěn)定的好處:
減小包體積:iOS 12.2 以前版本福青,用 Swift 開發(fā)的 App 打包時需要將當(dāng)前版本的 Swift 內(nèi)置動態(tài)庫打包進(jìn)去摄狱;而 iOS 12.2 及以上版本脓诡,系統(tǒng)內(nèi)置了 Swift 動態(tài)庫,不用每個 App 單獨內(nèi)置媒役,大大減小了包體積(實際減小的包體積大小和 App 用到的 Swift 標(biāo)準(zhǔn)庫和系統(tǒng)版本都有關(guān)系)祝谚。
節(jié)省內(nèi)存:所有 App 使用同一個 Swift 運(yùn)行時, App 啟動不需要額外加載內(nèi)置 Swift 動態(tài)庫刊愚,在 iOS 12.2 及以上系統(tǒng)會更節(jié)省內(nèi)存踊跟。
減小啟動耗時:同理,在 iOS 12.2 及以上系統(tǒng)因為啟動時無需加載內(nèi)置 Swift 動態(tài)庫鸥诽,也節(jié)省了啟動耗時商玫。
不強(qiáng)依賴編譯器:ABI 穩(wěn)定之前,兩個二進(jìn)制組件需在同一編譯器下編譯牡借。ABI 兼容性保障應(yīng)用程序和各二進(jìn)制組件可以分開編譯拳昌,不強(qiáng)依賴編譯器,應(yīng)用和二進(jìn)制形態(tài)組件也不用在同一編譯器下編譯钠龙。
Pure Swift:對于 Apple 工程師來說炬藤,可以直接在系統(tǒng)框架使用 Swift,而不必用 Objective-C 來 wrap 一遍碴里,運(yùn)行效率更高沈矿,維護(hù)成本更低。得益于 ABI 穩(wěn)定咬腋,在 2019 年羹膳,Apple 也確實推出了 SwiftUI、RealityKit根竿、Combine陵像、CreateML 4個 Pure Swift 框架。
1.3 Module 穩(wěn)定
Swift 庫和庫的 API 以 module 的方式導(dǎo)出寇壳,module 文件被編譯創(chuàng)建和使用醒颖。Swift 5.1 引入了穩(wěn)定基于文本的 module 接口文件,不同版本的編譯器具備兼容性壳炎。Module 穩(wěn)定使我們創(chuàng)建的 Swift framework 能夠兼容未來的 Swift 版本泞歉。Module 穩(wěn)定代表著描述模塊 API 的信息格式穩(wěn)定。這個信息會在編譯時使用匿辩,它表明了這個庫所有的類和函數(shù)都是什么疏日,如同 C 語言的 header 文件一樣。Swift 把這個信息存在一個名為 .swiftmodule 的二進(jìn)制文件中撒汉。由于這個文件在不同編譯器間不兼容沟优,這意味著如果應(yīng)用程序開發(fā)人員無法使用其他版本的 Swift 編譯器引入該 framework。
Swift 5.1 實現(xiàn)了一個文本的方案來實現(xiàn) Module 穩(wěn)定睬辐,使用一個名為 .swiftinterface 的文本文件替換二進(jìn)制的 .swiftmodule 文件挠阁,內(nèi)容類似于 Xcode 中 swift 文件的 generated interface宾肺。
例如,你可以使用 Swift 6 構(gòu)建框架侵俗,而該框架的接口將可由 Swift 6 和以后的 Swift 7 編譯器讀取锨用。
Swift 不同版本的編譯器編譯出的產(chǎn)物可以互相引用,不會出現(xiàn)以下錯誤:
“Module compiled with Swift 5.1 cannot be imported by the Swift 5.2 compiler”
1.4 Library Evolution
Library Evolution 允許二進(jìn)制組件發(fā)生變化時隘谣,不用再重新編譯其宿主增拥。這樣無論是系統(tǒng)框架發(fā)生變化時,還是開發(fā)者依賴的第三方框架發(fā)生變化時寻歧,開發(fā)者都不需要重新編譯自己的應(yīng)用(或框架)就能直接運(yùn)行掌栅。
在此示例中,應(yīng)用是基于框架的原始版本(黃色)構(gòu)建的码泛。由于 Library Evolution猾封,它可以運(yùn)行在包含黃色版本框架的系統(tǒng)上,也可以直接運(yùn)行在升級后的紅色版本框架的系統(tǒng)上噪珊。
1.5 ABI 穩(wěn)定 晌缘、 Module 穩(wěn)定和 Library Evolution
Swift 具有的特性 | 支持 | 狀態(tài) |
---|---|---|
ABI 穩(wěn)定 | 應(yīng)用程序能在更高版本的 Swift 標(biāo)準(zhǔn)庫環(huán)境下運(yùn)行 | Swift 5 之后開始支持 |
Module 穩(wěn)定(并且 ABI 穩(wěn)定) | 組件能在更高版本的編譯器環(huán)境下被引用 | Swift 5.1 之后開始支持 |
Library Evolution | 二進(jìn)制組件在發(fā)生改變時,只要 API 向前兼容痢站,引用它的宿主無須重新編譯 | Swift 5.1 之后開始支持 |
1.6 開源社區(qū):
從圖中可以看到磷箕,從 2016 年年中開始,github Swift 代碼 push 的量已經(jīng)超過了 OC阵难,Swift 的新活躍開源項目也遠(yuǎn)超過 OC搀捷。開源推動了外部貢獻(xiàn)者參與 Swift 生態(tài)建設(shè),長期看 OC 三方開源庫面臨年久失修和新功能不支持的風(fēng)險多望。
1.7 官方推薦
Apple 已經(jīng)在開發(fā)文檔中將 Swift 設(shè)置為默認(rèn)示例語言,2019年 WWDC 發(fā)布了4個純 Swift 的 Framework氢烘,不排除后面發(fā)布的 Framework 只有 Swift 版本的可能怀偷;另外 Apple 也積極開展高校合作,目前在美國已經(jīng)有 18 所大學(xué)和學(xué)院將 Swift 納入教學(xué)課程播玖,同時也開發(fā)了面向高中和高等院校的《使用 Swift 開發(fā)》課程椎工,和面向 4 年級至 8 年級學(xué)生的《人人能編程》課程;隨著 Swift 語言的普及和編程門檻的降低蜀踏,我們能做的就是為優(yōu)秀的 Swift 開發(fā)者敞開大門维蒙。
另外,OC 和 Swift 也有良好的互操作性果覆。至此颅痊,所有準(zhǔn)備工作已就緒,對 iOS 開發(fā)者來說普及已經(jīng)是大勢所趨了局待。
二. Swift 的優(yōu)勢
2.1 開發(fā)效率
Swift 擁有簡單而富有表現(xiàn)力的語法斑响,即使你以前沒有任何編碼經(jīng)驗菱属,也很容易理解。事實上舰罚,根據(jù)蘋果公司的說法纽门,Swift 被設(shè)計成第一種供任何人學(xué)習(xí)的編程語言。Swift 也同時吸收了很多語言的特性, 以至于各種不同語言的開發(fā)者寫 Swift 的時候都會覺得特別熟悉特別親切营罢。以下是 Swift 從其他語言借鑒的特性或表示方法:
Dictionaries(或Hash Table):簡潔的中括號初始化語法從 JavaScript 而來赏陵。
數(shù)據(jù)類型推斷:編譯器通過變量的初始值很容易推斷變量的數(shù)據(jù)類型。這個功能最早出現(xiàn)在 Haskell饲漾、Scala蝙搔、Opa、微軟也在 .Net 3.0 中引入了這個功能能颁。
泛型數(shù)據(jù)結(jié)構(gòu)聲明:Java 5 引入了泛型杂瘸,通過尖括號中的數(shù)據(jù)類型,告訴編譯器 HashMap伙菊,Array败玉,Collection 等集合類中存儲了何種數(shù)據(jù)類型。同一時間微軟把這一功能引入到 C# 中镜硕。
字符串模板:從 Cold Fusion运翼、JSP 等語言而來。
程序行尾可選分號:從 JavaScript兴枯、Python 而來血淌。
Protocol(或 Interface):從 Java 和 C# 而來。
-
元組(Tuples):元組是通過逗號分割财剖,小括號括起來的類型列表悠夯,可以讓一個函數(shù)有多個返回值,這種特性從 Lisp 和 Python 而來躺坟。
圖片 閉包:閉包的概念出現(xiàn)于 60 年代沦补,最早實現(xiàn)閉包的程序語言是 Scheme。之后咪橙,閉包被廣泛使用于函數(shù)式編程語言如 ML 語言和 LISP夕膀。
協(xié)程(async/await):即將引入的協(xié)程,作為取代線程的更優(yōu)雅的異步模型美侦,來源于 Smalltalk产舞、Ruby、Lua菠剩、Julia 和 Go 等語言易猫。(Coming soon)
畢加索:(Good artists borrow, Great artists steal)
2.2 安全
<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; outline: 0px; max-width: 100%; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); letter-spacing: 0.5440000295639038px; tab-size: 4; white-space: pre-wrap; font-size: 14px; text-align: left; box-sizing: border-box !important; word-wrap: break-word !important;">Swift 語言的語法鼓勵你編寫簡潔一致的代碼,有時甚至?xí)兊脟?yán)格具壮,同時提供了保護(hù)措施以防止錯誤并提高可讀性擦囊。</pre>
靜態(tài)類型語言:IDE 在編譯前就會檢查代碼中的錯誤违霞,類型檢查更加嚴(yán)格。
類型推斷:編譯器可以在編譯代碼的時候通過表達(dá)式的值自動推斷出表達(dá)式的類型瞬场。
guard: 我們可以使用 guard 語句來對后面的代碼塊加以保護(hù)买鸽,使代碼塊在未滿足條件時能提前正常返回(return)或結(jié)束循環(huán)(break/continue)或異常退出(throw/fatalError())。
optional:默認(rèn)情況下贯被,Swift 對象不能定為 nil — 這在另一方面保證了 Swift 的安全性眼五。實際上,Swift 編譯器會在你嘗試創(chuàng)建或使用 nil 對象時顯示編譯時錯誤彤灶,阻止你繼續(xù)操作看幼。這使得代碼編寫變得更簡潔、更安全幌陕,并且可以防止 app 中出現(xiàn)大量的運(yùn)行時崩潰诵姜。但是,在某些情況下搏熄,運(yùn)用 nil 是適當(dāng)合理的棚唆。針對這類情況,Swift 提供了一項創(chuàng)新功能心例,稱為“可選類型”宵凌。可選類型可以包含 nil止后,但是 Swift 語法會強(qiáng)制要求你使用 ? 語法來安全地處理 nil瞎惫。使用該語法,等于向編譯器表明你理解此行為并將安全地進(jìn)行處理译株。
2.2 編譯優(yōu)化
-
SIL(Swift Intermediate Language):SIL 會對 Swift 進(jìn)行較高級別的語義分析和優(yōu)化瓜喇。包括高級別的語義分析,診斷轉(zhuǎn)換歉糜,去虛擬化乘寒,特化,引用計數(shù)優(yōu)化现恼,TBAA(Type Based Alias Analysis)等。
圖片 WMO:全模塊編譯優(yōu)化黍檩。首先叉袍,編譯器了解模塊中所有函數(shù)的實現(xiàn),所以它能夠執(zhí)行諸如函數(shù)內(nèi)聯(lián)和函數(shù)特殊化等優(yōu)化刽酱。函數(shù)特化主要應(yīng)該是指通過調(diào)用上下文傳遞的類型來生成一個基于特定類型的版本喳逛。但是很多情況下,會導(dǎo)致二級制級別的代碼膨脹棵里。有了全模塊優(yōu)化润文,能夠把多處基于相同類型生成的函數(shù)優(yōu)化為一個姐呐。
2.3 運(yùn)行性能
靜態(tài)類型語言:靜態(tài)類型語言比動態(tài)類型語言更快,因為類典蝌、方法曙砂、數(shù)據(jù)類型定義更清晰,編譯器可以進(jìn)行內(nèi)聯(lián)等優(yōu)化骏掀、減少為支持引用類型而額外分配的內(nèi)存空間鸠澈,同時由于采用靜態(tài)派發(fā)的方式也大幅提高了運(yùn)行時方法的調(diào)用效率。
靜態(tài)派發(fā):是在編譯期就能確定的調(diào)用方法的派發(fā)方式截驮。靜態(tài)派發(fā)相比于動態(tài)派發(fā)更快笑陈,而且靜態(tài)派發(fā)還會進(jìn)行內(nèi)聯(lián)等一些優(yōu)化,減少函數(shù)的尋址及內(nèi)存地址的偏移計算等一系列操作葵袭,使函數(shù)的執(zhí)行速度更快涵妥,性能更高。
Fast, Whole Module Optimization:開啟 -O -whole-module-optimization坡锡,Swift 編譯器將會同時考慮整個 module 中所有源碼的情況蓬网,并將那些沒有被繼承和重載的類型和方法標(biāo)記為 final,這將盡可能地避免動態(tài)派發(fā)的調(diào)用娜氏,或者甚至將方法進(jìn)行內(nèi)聯(lián)處理以加速運(yùn)行拳缠。
結(jié)構(gòu)體:結(jié)構(gòu)體除了屬性的存儲更安全、效率更高之外贸弥,其函數(shù)的派發(fā)也更高效窟坐。由于結(jié)構(gòu)體不能被繼承,也就是結(jié)構(gòu)體的類型被 final 修飾绵疲,其內(nèi)部函數(shù)應(yīng)該是屬于靜態(tài)派發(fā)哲鸳,在編譯期就確定了函數(shù)的執(zhí)行方式,其函數(shù)的調(diào)用通過內(nèi)聯(lián)(inline)的方式進(jìn)行優(yōu)化盔憨,其內(nèi)存連續(xù)徙菠,減少了函數(shù)的尋址及內(nèi)存地址的偏移計算,其運(yùn)行相比于動態(tài)派發(fā)更加高效郁岩。
Swift 的運(yùn)行效率甚至能比肩 C++婿奔。可以參考 http://www.primatelabs.com/blog/2014/12/swift-performance/ 對 Swift 和 C++ 性能的比較问慎。
2.4 內(nèi)存管理
ARC:OC ARC 支持范圍包含 Cocoa Touch framework萍摊,但不包含 CoreGraphics、CoreFoundation 等底層框架如叼;Swift 所有 API 都支持 ARC冰木。
COW:Copy On Write,寫時復(fù)制,Swift 針對標(biāo)準(zhǔn)庫中的集合類型(Array踊沸、Dictionary歇终、Set)進(jìn)行優(yōu)化,當(dāng)變量指向的內(nèi)存空間并沒有發(fā)生改變,進(jìn)行拷貝時逼龟,并沒有真正發(fā)生拷貝评凝,而是指向原來的內(nèi)存。只有當(dāng)值發(fā)生改變時才會進(jìn)行深拷貝审轮。
值類型:在 Swift 中定長的值類型都是保存在棧上的肥哎,操作時不會涉及堆上的內(nèi)存。變長的值類型(字符串疾渣、集合類型是可變長度的值類型)會分配堆內(nèi)存篡诽。
引用類型:引用類型的存儲屬性不會直接保存在棧上,系統(tǒng)會在棧上開辟空間用來保存實例的指針榴捡,棧上的指針負(fù)責(zé)去堆上找到相應(yīng)的對象杈女。
所有權(quán):獨占性原則——阻止以互相沖突的方式同時訪問某個變量 ;允許被“共享”的值傳遞下去吊圾;允許標(biāo)記某個類型不能被隱式復(fù)制达椰。(Coming soon)
三. Swift 使用現(xiàn)狀
3.1 百度App 及矩陣產(chǎn)品
全量工程化和工程改造前,百度App 在 Watch App项乒、各獨立 Widget啰劲、以及很少一部分 SDK 中使用 Swift。不過百度內(nèi)部 檸檬愛美檀何、古物潮玩蝇裤、有噗等創(chuàng)新產(chǎn)品都廣泛的使用 Swift 開發(fā)。
3.2 國內(nèi)其他 App
根據(jù)現(xiàn)有公開資料频鉴,我們了解到手淘已全面支持 Swift栓辜,微信部分使用 Swift,今日頭條的飛書(Lark)使用了 Swift垛孔。
3.3 國外 App
這篇文章(https://blog.csdn.net/Desgard_Duan/article/details/105872728)統(tǒng)計了國內(nèi)外使用的 Swift 開發(fā)的 Top 100 應(yīng)用列表藕甩,但并不明確各 App Swift 的應(yīng)用范圍,也不明確各 App 已經(jīng)系統(tǒng)化解決 OC 和 Swift 在大型工程或組件化開發(fā)模式下的問題周荐。
四. 影響面評估
4.1 應(yīng)用體積的影響
對于 iOS 12.2 以下的系統(tǒng)狭莱,使用 Swift 編寫的代碼打包成 App 后需要額外內(nèi)置 Swift 動態(tài)庫。而 iOS 12.2 及以上版本概作,使用 Swift 5.0 以上編寫的 Swift 代碼腋妙,不再需要打包 Swift 運(yùn)行時,相比之前仆嗦,減小了 7.9 MB辉阶。
在"Swift 的優(yōu)勢"部分先壕,我們已經(jīng)看到 Swift 在開發(fā)效率瘩扼、安全性谆甜、運(yùn)行性能、內(nèi)存管理方面的優(yōu)勢集绰,也無明顯劣勢规辱,所以普及也是順其自然的事情了。
五. 落地步驟
在單工程源碼模式下栽燕,我們?yōu)?Swift 訪問 OC 建立 bridge 文件罕袋,Swift 編譯時也會生成 *-Swift.h 頭文件供 OC 調(diào)用;這樣就可以實現(xiàn) OC 和 Swift 混合開發(fā)碍岔。
在以并行開發(fā)浴讯,或者以 App 工廠為目標(biāo)的 App ,都會對工程進(jìn)行組件化拆分蔼啦,不僅需要依賴管理工具的支撐榆纽,也需要對工程進(jìn)行改造。百度App 目前使用組件化模式開發(fā)捏肢,同時兼容 源碼奈籽、二進(jìn)制 兩種組件形態(tài);因此需要保障組件間互操作性鸵赫,保障對源碼衣屏、二進(jìn)制兩種形態(tài)下的組件編譯、鏈接過程的完整支撐辩棒。
百度App 整體落地步驟如下:
Swift 優(yōu)勢調(diào)研
影響面評估
編碼規(guī)范制定及約束工具開發(fā)
EasyBox 工具鏈混編支持
工程改造與實踐
這篇文章介紹了前兩部分狼忱,Swift 編碼規(guī)范及約束工具有創(chuàng)新團(tuán)隊同學(xué)提供支持。后面兩篇文章將重點介紹這里面的兩個重點環(huán)節(jié)盗温,工具鏈層面系統(tǒng)化支持 OC 和 Swift 混編藕赞,以及如何進(jìn)行工程改造以支撐全面Swift全面應(yīng)用開發(fā)。
六. 參考
WWDC 2019 - What's New In Swift:
https://devstreaming-cdn.apple.com/videos/wwdc/2019/402fd460n3p3w5c/402/402_whats_new_in_swift.pdf?dl=1WWDC 2016 - Understanding Swift Performance:
https://developer.apple.com/videos/play/wwdc2016/416/What is Module Stability in Swift and why should you care?
https://www.donnywals.com/what-is-module-stability-in-swift-and-why-should-you-care/ABI Stability and More:
https://swift.org/blog/abi-stability-and-more/一次關(guān)于 Swift 在 iOS 生態(tài)圈里的現(xiàn)狀調(diào)研:
https://blog.csdn.net/Desgard_Duan/article/details/105872728手淘航母級 App 戀上 Swift 之路:
https://mp.weixin.qq.com/s/_ecHx0-r_od1-AfpYNvchgSwift vs Objective-C: Out with the Old, In with the New:
https://www.altexsoft.com/blog/engineering/swift-vs-objective-c-out-with-the-old-in-with-the-new/10 features Apple 'stole' for the Swift programming language:
https://www.infoworld.com/article/2606431/155797-10-prominent-features-stolen-by-Apple-s-Swift-and-where-they-came-fro.html#slide12Writing High-Performance Swift Code:
https://github.com/apple/swift/blob/master/docs/OptimizationTips.rstSwift 性能探索和優(yōu)化分析:
https://onevcat.com/2016/02/swift-performance/Swift Concurrency Manifesto:
https://gist.github.com/lattner/31ed37682ef1576b16bca1432ea9f782Ownership Manifesto:
https://github.com/apple/swift/blob/main/docs/OwnershipManifesto.mdSwift性能優(yōu)化分析:
https://juejin.cn/post/688786214412648449Swift, C++ Performance:
http://www.primatelabs.com/blog/2014/12/swift-performance/
相關(guān)文章:
Swift 官方文檔:https://docs.swift.org/swift-book/
Swift 中文教程:https://swiftgg.gitbook.io/swift/
-
API Design Guidelines 中文版:
https://github.com/SketchK/the-swift-api-design-guidelines-in-chinese