前言:
最近幾天在看《100個Swift必備tips》這本書婿失,本篇為讀書筆記体斩,以作總結(jié)記錄用猜欺。
將protocol
的方法聲明為mutating
:
在swift
里,protocol
中定義的方法既可以被class
實現(xiàn)吮龄,也可以被struct
和enum
來實現(xiàn)俭茧。但若是被后兩者實現(xiàn),默認(rèn)情況下漓帚,實現(xiàn)的方法內(nèi)部是無法更改struct
和enum
變量母债。若你將要定義的協(xié)議可能需要被struct
或enum
實現(xiàn),請在定義協(xié)議方法時尝抖,加上關(guān)鍵字mutating
场斑。
為方便起見,若定義的協(xié)議需要被struct
或enum
實現(xiàn)牵署,建議在協(xié)議中定義方法時均添加mutating
關(guān)鍵字漏隐。無論你定義的方法需不需要更改變量。
Sequence 協(xié)議:
Swift 中的 Sequence(一)
Swift 中的 Sequence(二)
元組Tuple:
讓我們想想奴迅,在C或OC中我們想讓函數(shù)返回多個值時青责,應(yīng)該怎么實現(xiàn)?你可以將多個返回值拼裝成一個Dictionary
或Model
再返回取具。你還可以使用“指針類型參數(shù)”來傳遞值脖隶。
CGRect small;
CGRect large;
CGRectDivide(self.view.bounds, &small, &large, 20, CGRectMinXEdge);
在Swift
中,就變得很簡單了暇检,只需返回一個Tuple
就可以了产阱。對于元組里的元素,既可以像數(shù)組那樣通過下標(biāo)來訪問块仆,也可以像字典那樣通過key
來訪問构蹬。
可選鏈:
像下面的代碼,即便Toy
類中的name
屬性不是可選型的悔据,但是最終獲取到的結(jié)果toyName
仍然是可選的庄敛,因為在整個調(diào)用鏈條中pet
,toy
都是可選的,都有可能為nil
科汗,而提前中止調(diào)用鏈條藻烤,返回nil
。
既然返回了nil
,就說明結(jié)果是可選的怖亭,是String?
型的涎显。因此,我們要用if let
語句來解包兴猩。
if let toyName = xiaoming.pet?.toy?.name {
}
使參數(shù)可變 inout:
Swift
中期吓,方法參數(shù)默認(rèn)是不可變的,不能在方法內(nèi)部修改參數(shù)的值峭跳。
若你真的想直接修改參數(shù)的值膘婶,則需用inout
關(guān)鍵字來修飾參數(shù)缺前。 如此蛀醉,則在方法內(nèi)部就可以直接修改參數(shù)了,且inout
讓參數(shù)具有了“傳址調(diào)用”的能力衅码,因此在調(diào)用時要在參數(shù)名前加&
拯刁。
下面代碼定義了一個將變量重置為0的方法reset
func reset(x: inout Int) {
x = 0;
}
var x = 5
self.reset(x: &x)
print("result:x=\(x)")
// log: result:x=0
自定義下標(biāo) subscript:
在編程語言中,都可以以下標(biāo)來訪問Array
逝段、Dictionary
等集合對象垛玻。
在Swift
中可就更厲害了,它支持給任何類奶躯、結(jié)構(gòu)體和枚舉自定義下標(biāo)帚桩,使它們都可以以下標(biāo)的形式被訪問。
無論是項目中你自己定義的類嘹黔,還是原先就有下標(biāo)的集合類账嚎,你都可以自定義下標(biāo)訪問它們!
自定義下標(biāo)儡蔓,用subscript
關(guān)鍵字郭蕉,非常類似用關(guān)鍵字init
自定義構(gòu)造器。
比如下面的代碼喂江,我們拓展了Array
的下標(biāo)召锈,使其下標(biāo)可以為數(shù)組,讀寫任意位置的元素获询。
extension Array {
subscript(indexs: [Int]) -> [Element] {
get {
var resultArr = [Element]()
for index in indexs {
assert(index<self.count, "index out of range")
resultArr.append(self[index])
}
return resultArr
}
set {
for (index, i) in indexs.enumerated() {
assert(i<self.count, "index out of range")
self[i] = newValue[index]
}
}
}
}
var array = [1, 2, 3, 4, 5, 6]
let resultArr = array[[0,1,2]] // 獲取下標(biāo)[1,2,3]的值
print(resultArr)
// log ————> [1,2,3]
array[[0,1,2]] = [0,0,0] // 修改下標(biāo)[1,2,3]的值
print(array)
// log ————> [0,0,0,4,5,6]
Any 和 AnyObject:
簡單來說涨岁,AnyObject
表示任何class
類型;
Any
表示任何類型,包括任何class
烟馅、struct
逊彭、enum
類型。
我們知道沮尿,在OC
中id
代表任何類型,并也有經(jīng)常見于Cocoa
框架中,而Swift
用的框架仍為Cocoa
畜疾。為了能完美對接赴邻,Swift
不得不發(fā)明個與OC
中id
相對應(yīng)的類型,這便是AnyObject
的來歷啡捶。(AnyObject
其實是個協(xié)議姥敛,Swift
中的所有class
均實現(xiàn)了該協(xié)議。)
但是很遺憾的是瞎暑,Swift
中的所有的基本類型彤敛,包括Array
和Dictionary
這些在OC
中為class
的東西,統(tǒng)統(tǒng)都是struct
了赌。
所以墨榄,蘋果就又新增了更特殊,更強(qiáng)大勿她,能代表任何類型的Any
袄秩。
多類型和容器:
按理說,數(shù)組中存入的元素都應(yīng)該是類型相同的逢并。但是在Swift
中有Any
和AnyObject
這兩個很特殊的之剧,代表任何類型的類型。試想:若我們在定義數(shù)組時砍聊,將數(shù)組元素申明為Any
或AnyObject
背稼,是不是就可以存入不同類型的元素了。不管是Int
還是String
玻蝌,它們也是Any
和AnyObject
類型啊蟹肘。
let array: [Any] = [1, "string"]
這樣確實是可以的,但這樣是極不安全的灶伊,我們將其以Any
的方式存入數(shù)組疆前,是一種類型提升,這樣會丟失很多原本具有的數(shù)據(jù)聘萨。若你從該數(shù)組中取出string
竹椒,它便不具備原本String
具有的能力了,包括屬性和方法等米辐。此時胸完,若你調(diào)用這些屬性或方法的話,程序就會出問題翘贮。
其實赊窥,數(shù)組中存入的元素,并不一定必須得是相同類型的狸页,也可以是實現(xiàn)同一協(xié)議的不同類型锨能。
像下面這樣扯再,因為Int
和String
本身都是實現(xiàn)了CustomStringConvertible
協(xié)議的。我們可以將數(shù)組申明為『實現(xiàn)了CustomStringConvertible
協(xié)議』的類型址遇。
let array: [CustomStringConvertible] = [1, "string"]
for item in array {
print(item.description);
}
public protocol CustomStringConvertible {
public var description: String { get }
}
還有另一種做法是使用enum
可以帶有值的特點熄阻,將類型信息封裝到特定的enum
中。下面定義了一個枚舉AnyType
倔约。
enum AnyType {
case IntType(Int)
case StringType(String)
}
let mixedArr = [AnyType.IntType(1), AnyType.StringType("string")]
for item in mixedArr {
switch item {
case let .IntType(i):
print(i)
case let .StringType(str):
print(str)
}
}
屬性觀察:
Swift
讓屬性觀察這件事變得異常簡單秃殉。下面代碼觀察了People
類的count
屬性,若其值小于0浸剩,則打印提示信息钾军。
class People: NSObject {
var count: Int {
willSet {
print("count----willSet")
}
didSet {
print("count----didSet")
if(count<0){
print("count不能小于0")
}
}
}
override init() {
count = 0
}
}
let people = People()
people.count = -10
需要注意的是,Swift
中的屬性有『存儲屬性』和『計算屬性』之分绢要。前者會在內(nèi)存中實際分配地址來存儲屬性吏恭,而后者并不是實際存于內(nèi)存的,它只是通過提供get
和set
兩個方法來訪問袖扛,讀寫該屬性(它和普通的方法很類似)砸泛。
Swift
中的『計算型屬性』是無法使用willSet
/didSet
屬性觀察的十籍,也就是說在定義屬性時蛆封,不能同時出現(xiàn)set
和willSet
/didSet
。因為要監(jiān)聽計算型屬性勾栗,我們完全可以在set
里面添加監(jiān)聽屬性的處理代碼惨篱。
有時,我們往往需要觀察一個屬性围俘,但是砸讳,這個屬性是別人定義的,我們不便直接在源代碼里寫didSet
用以監(jiān)聽界牡。此時簿寂,子類化該類,重寫其屬性宿亡,在重寫中對該屬性添加didSet
監(jiān)聽是個很好的解決方案常遂。
更值得說的是: 子類化該類,重寫其屬性挽荠,然后添加didSet
監(jiān)聽克胳,竟然可以用在父類是計算型屬性的情況下。也就是說圈匆,這也是解決Swift
中計算型屬性無法寫didSet
監(jiān)聽的一種方案了漠另,即把didSet
寫到子類重寫的屬性中去。
單例的最正確寫法:
用兩個關(guān)鍵字static let
修飾跃赚,可以限制sharedInstance
是全局且不可變的笆搓,這就有了『單例』的意思了。但是還不夠,還要堵住其他構(gòu)造途徑满败,防止調(diào)用其他構(gòu)造器創(chuàng)建實例窘奏,所以在原本的init
方法前加上了private
關(guān)鍵字。
class UserInfoManager: NSObject {
static let sharedInstance = UserInfoManager()
private override init() {}
}
let userInfo = UserInfoManager.sharedInstance
@UIApplicationMain:
對于一個Objective-C
的iOS項目葫录,Xcode會自動幫我們生成一個main.m
文件着裹,其中有個main
函數(shù)。
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
main
函數(shù)里調(diào)用了UIKit
的UIApplicationMain
方法米同,這個方法根據(jù)第三個參數(shù)初始化一個UIApplication
或者子類的對象并開始接收事件(默認(rèn)傳入的是nil
骇扇,意味使用默認(rèn)的UIApplication
)。最后一個參數(shù)指定了AppDelegate
類作為委托面粮,用來接收didFinishLaunchingWithOptions:
和applicationDidEnterBackground:
等有關(guān)程序生命周期的方法少孝。
后兩個參數(shù)都可以傳入自定義的子類來完成更加個性化的需求。
另外熬苍,main
函數(shù)雖然標(biāo)明返回一個int
稍走,但是它不會真正返回。它會一直存在于內(nèi)存中柴底,直到用戶或系統(tǒng)將其強(qiáng)制終止婿脸。
..... 現(xiàn)在,我們來看看在Swift
中情況是怎樣的柄驻。
可以看到狐树,在Swift
的iOS項目中找不到main.m
文件,但是卻在AppDelegate
類開頭多了個@UIApplicationMain
標(biāo)簽鸿脓。其實抑钟,這個標(biāo)簽的作用就是上面所說的main
函數(shù)的作用:
初始化一個默認(rèn)為UIApplication
類的實例來接收事件,指定AppDelegate
為委托來接收程序生命周期方法野哭。
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
...
...
}
所以說在塔,Swift
的iOS項目中,并不是不需要main
函數(shù)拨黔,而是通過添加@UIApplicationMain
標(biāo)簽蛔溃,Xcode幫我們自動處理了main
函數(shù)的邏輯。
當(dāng)然蓉驹,這個標(biāo)簽并不是必須的城榛,若你需要指定子類化的UIApplication
和AppDelegate
,則可以自己給項目中添加個main.m
文件态兴,實現(xiàn)main
函數(shù)狠持,并指定這兩個子類化的實例為參數(shù)。
如何動態(tài)地獲取一個實例的類型:
方法一瞻润,若類是繼承于NSObject
類的喘垂,則我們可以利用OC
的運行時:
public func object_getClass(_ obj: Any!) -> Swift.AnyClass!
let people = People()
let peoType: AnyClass! = object_getClass(people)
print(peoType)
// log ----> People
方法二:用一個全局的函數(shù)type(of:)
甜刻,如下:
let people = People()
let peoType = type(of: people)
print(peoType)
// log ----> People
// type(of:)
方法是Swift3.0
新增的,代替了前期版本中的dynamicType
屬性(Swift3.0
之前正勒,使用該屬性可返回該對象的類型)得院。
自省:
自收抡辍:向一個對象發(fā)出詢問祥绞,以確定它是不是屬于某個類,這種操作就稱為“自省”鸭限。
在OC
中我們是這樣判斷一個對象是不是屬于某個類的:
if([_type isKindOfClass:[NSString class]]){
}
在Swift
中蜕径,若該類是繼承自NSObject
的,則也有上面相應(yīng)的兩個方法:
class People: NSObject {
}
let peo = People()
if peo.isKind(of: People.self) {
print("isKind")
}
if peo.isMember(of: People.self) {
print("isMember")
}
除此外败京,Swift
提供了更強(qiáng)大簡潔的關(guān)鍵字is
兜喻,同樣能達(dá)判斷類型的效果。
而且is
的強(qiáng)大在于赡麦,它不僅適用于class
朴皆,在struct
和enum
中,它同樣是可用的泛粹。
if peo is People {
print("isKind")
}
KVO:
Swift
中也可以使用KVO
,但是僅限于在NSObject
子類中遂铡。因為KVO
是基于KVC
和動態(tài)派發(fā)技術(shù)的,而這些都是NSObject
運行時的概念戚扳。另外忧便,由于Swift
為了提高效率族吻,默認(rèn)禁止了動態(tài)派發(fā)帽借,因此想用Swift
使用KVO
的話,還要將被觀測的對象標(biāo)為dynamic
超歌。
簡單來說砍艾,Swift
要使用KVO
有兩個限制:
1.被觀測的對象屬于NSObject
類;2.被觀測的對象屬性被標(biāo)為dynamic
巍举。
下面的代碼脆荷,我們觀察People
類里的money
屬性,它即為被觀測的對象懊悯,所以要將其標(biāo)為dynamic
蜓谋。
class People: NSObject {
dynamic var money = 0 // 標(biāo)為dynamic
}
給people
的money
屬性添加觀察,并重寫回調(diào)方法炭分,在其中拿到改變后的新值桃焕。并且,一定要記得在deinit
方法中移除觀察捧毛。
private var myContext = 0
class ViewController: UIViewController {
var people = People()
override func viewDidLoad() {
super.viewDidLoad()
// 添加觀察
people.addObserver(self, forKeyPath: "money", options: .new, context: &myContext)
people.money = 3
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let change = change, context == &myContext{
let newValue = change[NSKeyValueChangeKey.newKey]
if let newValue = newValue {
print(newValue)
}
}
}
deinit {
people.removeObserver(self, forKeyPath: "money")
}
}
但是观堂,在實際開發(fā)過程中让网,我們往往會遇到不符合上述兩點的情況港令,那在這種情況下骏掀,我們還能不能使用KVO
呢根欧?
若被觀測的對象不繼承自NSObject
的話隐轩,那真的無法使用KVO
,只能自己利用“屬性觀察”自己實現(xiàn)一套觀察機(jī)制(在didSet
里發(fā)送通知炭臭,通知外界屬性值已改變)奶镶。
若被觀測的對象我們無法直接標(biāo)為dynamic
羹奉,比如系統(tǒng)類的對象鲫尊。那我們可以子類化該類笔横,重寫該屬性惜犀,重寫時將其標(biāo)為dynamic
。
如下面的例子狠裹,假如我們要對People
的money
屬性進(jìn)行觀測虽界,但是又不方便或不允許將money
屬性標(biāo)為dynamic
,所以我們新建繼承自People
的ChildPeople
類涛菠,在其中重寫money
時將其標(biāo)為dynamic
莉御。
class People: NSObject {
var money = 0
}
class ChildPeople: People {
dynamic override var money: Int {
get {
return super.money
}
set {
super.money = newValue
}
}
}
判等:
我們可以實現(xiàn)Equatable
中的上面方法,來完成自定義對象判等邏輯俗冻。NSObject
實現(xiàn)了Equatable
協(xié)議礁叔,若類是繼承自NSObject
的,則不需我們自己實現(xiàn)該協(xié)議迄薄。
像下面代碼琅关,我們自定義了People
對象的判等邏輯:只要倆人的錢一樣多,就相等讥蔽。
class People {
var money = 0
init(mon: Int){
money = mon
}
}
extension People: Equatable {
public static func ==(lhs: People, rhs: People) -> Bool {
return lhs.money == lhs.money
}
}
若類僅僅是繼承自NSObject
,而不自己實現(xiàn)該協(xié)議方法涣易,則==
操作符默認(rèn)是NSObject
里的實現(xiàn),即對指針引用對象內(nèi)存地址的比較冶伞。除非倆引用同一塊內(nèi)存地址新症,否則不相等。
Swift
里是用===
來比較引用的內(nèi)存地址是否相等响禽。
下面創(chuàng)建的people1
和people2
內(nèi)存地址是不同的徒爹,所以不會打印東西。
let people1 = People(mon: 10)
let people2 = People(mon: 10)
if people1===people2 {
print("===")
}
類簇:
字符串格式化:
OC
的字符串可以通過占位符%@
/%f
/%d
等芋类,將多個元素拼接成新的字符串隆嗅。
NSString *name = @"wang66";
NSString *str = [NSString stringWithFormat:@"%@%@", @"name =", name];
NSLog(@"%@",str);
在Swift
的字符串中則不需要占位符了,直接可以在字符串中插值侯繁。
let name = "wang66"
let str = "name = \(name)"
print(str)
// log ----> name = wang66
這樣確實非常簡潔了胖喳,但是若是出現(xiàn)將小數(shù)保留兩位小數(shù)的需求時該怎么辦呢?巫击,OC
中是這樣的:
CGFloat distance = 12.21424;
NSString *str = [NSString stringWithFormat:@"%0.2f%@", distance,@"km"];
NSLog(@"%@",str);
但是在Swift
中就不能繼續(xù)簡潔了禀晓,而是要用``String(format:)
let distance = 12.26578
let distanceStr = String(format: "%0.2f", distance)
let str = "\(distanceStr)km"
print(str)
// log ----> 12.27km
Options:
我們從UIView
的一個動畫方法說起精续,下面這個執(zhí)行動畫方法有個options
參數(shù),意為“選項”粹懒,用以配置動畫重付。在OC
中是這樣的:
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn|UIViewAnimationOptionCurveEaseOut animations:^{
NSLog(@"動畫進(jìn)行中...");
} completion:^(BOOL finished) {
NSLog(@"動畫完成...");
}];
options
參數(shù)是枚舉類型的,可以以|
將多個枚舉值連接凫乖,組合使用确垫。UIViewAnimationOptions
的定義如下,因為該參數(shù)允許組合枚舉各值帽芽,所以被定義成了支持掩碼位移的NS_OPTIONS
:(它和NS_ENUM
的區(qū)別主要是它自動支持掩碼位移)
typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) {
UIViewAnimationOptionLayoutSubviews = 1 << 0,
UIViewAnimationOptionAllowUserInteraction = 1 << 1, // turn on user interaction while animating
UIViewAnimationOptionBeginFromCurrentState = 1 << 2, // start all views from current value, not initial value
UIViewAnimationOptionRepeat = 1 << 3, // repeat animation indefinitely
UIViewAnimationOptionAutoreverse = 1 << 4, // if repeat, run animation back and forth
UIViewAnimationOptionOverrideInheritedDuration = 1 << 5, // ignore nested duration
UIViewAnimationOptionOverrideInheritedCurve = 1 << 6, // ignore nested curve
UIViewAnimationOptionAllowAnimatedContent = 1 << 7, // animate contents (applies to transitions only)
UIViewAnimationOptionShowHideTransitionViews = 1 << 8, // flip to/from hidden state instead of adding/removing
UIViewAnimationOptionOverrideInheritedOptions = 1 << 9, // do not inherit any options or animation type
而在Swift
中删掀,options
參數(shù)的情況卻大有不同。與上面OC
對應(yīng)的方法导街,在Swift
中是這樣的:
UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseIn, .curveEaseOut], animations: {
print("動畫進(jìn)行中...")
}) { isFinshed in
print("動畫結(jié)束...")
}
Swift
的枚舉無法支持位移賦值披泪。所以options
并不是枚舉,而是一個實現(xiàn)OptionSet
協(xié)議的struct
搬瑰,各個選項值為static
的get
屬性款票。
要達(dá)到像OC
中那樣多個選項值options
以|
符號組合,在Swift
中泽论,我們以集合包裝每個選項值艾少。 就像這樣:[.curveEaseIn, .curveEaseOut]
public struct UIViewAnimationOptions : OptionSet {
public init(rawValue: UInt)
public static var layoutSubviews: UIViewAnimationOptions { get }
public static var allowUserInteraction: UIViewAnimationOptions { get } // turn on user interaction while animating
public static var beginFromCurrentState: UIViewAnimationOptions { get } // start all views from current value, not initial value
public static var `repeat`: UIViewAnimationOptions { get } // repeat animation indefinitely
public static var autoreverse: UIViewAnimationOptions { get } // if repeat, run animation back and forth
weak delegate:
"委托代理"模式在iOS開發(fā)中可謂是最常用的模式,我們都知道翼悴,為了避免委托和代理對象互相引用缚够,無法釋放的問題,我們一般將委托的delegate
屬性標(biāo)為weak
弱引用鹦赎,主動示弱谍椅,以打破互相引用的僵局。
但是我們在Swift
中钙姊,我們不能直接在任何一個delegate
屬性前面加weak
關(guān)鍵字修飾毯辅。因為Swift
中的協(xié)議是可以被除了class
外的struct
和enum
來實現(xiàn)的,而后兩者它們是值類型煞额,它們不是通過引用計數(shù)規(guī)則來管理內(nèi)存的,所以當(dāng)然不能以weak
沾谜,這個ARC
里的東西修飾膊毁。
所以,在Swift
中使用“委托代理模式”基跑,首先要在定義協(xié)議時將其申明為只能被class
實現(xiàn)婚温。
protocol DemoDelegate: class {
func demoFunction()
}
或者,還有方案二:將定義的協(xié)議用@objc
申明為Objective-C
的媳否。因為在Objective-C
中栅螟,協(xié)議只能被class
實現(xiàn)荆秦。
@objc protocol DemoDelegate {
func demoFunction()
}
Swift 命令行工具:
啟動REPL(Read-Eval-Print Loop)
環(huán)境: 在終端輸入:xcrun swift
來啟動。
然后就可以“交互式編程”了力图,在終端每輸入代碼步绸,然后回車,就會實時編譯執(zhí)行吃媒。
試試定義一個方法瓤介,并調(diào)用∽改牵可以看到它甚至還可以反饋給我們錯誤提示刑桑,提示我“調(diào)用myFunction(5)
方法時缺少參數(shù)標(biāo)簽num
∧贾郏”
打印對象祠斧,自定義description:
我們打印一下People
的對象people
。
let people = People(name: "wang66", mobile: "18693133051", address: "白石洲")
print(people)
// log ----> <LearnAlamofireDemo.People: 0x6080000d6960>
可以看到打印信息只有對象的類型People
和內(nèi)存地址拱礁。但是這樣的信息幾乎沒什么用梁肿。
打印對象后展示什么信息,我們是可以定制的觅彰。
只要這個類實現(xiàn)CustomStringConvertible
協(xié)議吩蔑,然后重寫description
屬性,需要展示什么就return
什么填抬。
public protocol CustomStringConvertible {
public var description: String { get }
}
比如烛芬,我們在拓展中實現(xiàn)了自定制的description
屬性:
class People {
var name: String?
var mobile: String?
var address: String?
init(name: String?, mobile: String?, address: String?) {
self.name = name
self.mobile = mobile
self.address = address
}
}
extension People: CustomStringConvertible {
var description: String {
get {
return "[\(type(of:self)): name=\(self.name ?? "") | mobile=\(self.mobile ?? "") | address=\(self.address ?? "") ]"
}
}
}
打印結(jié)果如下,非常完美飒责。
let people = People(name: "wang66", mobile: "18693133051", address: "白石洲")
print(people)
// log ----> [People: name=wang66 | mobile=18693133051 | address=白石洲 ]
斷言 assert:
有時我們寫的方法是有數(shù)據(jù)傳入限制的赘娄,但是當(dāng)我寫的代碼別人調(diào)用,或者以后我自己調(diào)用時宏蛉,可能都不熟悉這個方法具體需要傳入什么條件的數(shù)據(jù)遣臼,這有可能讓大家浪費不必要的時間。最好拾并,在調(diào)用傳入數(shù)據(jù)時有反饋提示揍堰。
斷言,可以很好地解決這個問題嗅义。當(dāng)調(diào)用者傳入的數(shù)據(jù)不符合條件時屏歹,編譯不會通過,且會打印出提示信息之碗。
printYourAge(age: -10)
func printYourAge(age: Int) {
assert(age >= 0, "年齡都是正數(shù)")
print(age)
}