Swift2.0
1.defer譯為延緩铁蹈、推遲之意類似棧
注意作用域,其次是調(diào)用順序——即一個(gè)作用域結(jié)束(注意)十绑,該作用域中的defer語(yǔ)句自下而上調(diào)用(相同作用域下后入先執(zhí)行)漱挎。
不是函數(shù)結(jié)束時(shí)開(kāi)始執(zhí)行defer棧推出操作廉涕,而是每當(dāng)一個(gè)作用域結(jié)束就進(jìn)行該作用域defer執(zhí)行
2.guard有控制典蝌、警戒之意切記else中一定需要有返回的語(yǔ)句曙砂,比如return、continue骏掀、break鸠澈、throw這種提早退出的關(guān)鍵字!截驮!
guard age >= 13 else{
return
}
if age >= 13 else{
return
}
*/
//MARK:/******************************讀王巍*******************************/
/*
1.柯里化Swift里可以將方法進(jìn)行柯里化(Currying)14,也就是把接受多個(gè)參數(shù)的方法變換成接受第一個(gè)參數(shù)的方法,返回接受余下的參數(shù)并且返回結(jié)果的新方法笑陈。舉個(gè)例子,Swift中我們可以這樣寫出多個(gè)括號(hào)的方法
func addTwoNumbers(a: Int)(num: Int) -> Int {
return a + num
}
let addToFour = addTwoNumbers(4) // addToFour是一個(gè)Int -> Int方法
let result = addToFour(num: 6) // result = 10
2.Sequence(序列化)
Swift的for...in可以用在所有實(shí)現(xiàn)了SequenceType的類型上,而為了實(shí)現(xiàn)SequenceType你首先需要實(shí)現(xiàn)一個(gè)GeneratorType(發(fā)動(dòng)機(jī)類型)
class ReverseGenerator: GeneratorType {
typealias Element = Int
var counter: Element
init(array: [T]) {
self.counter = array.count - 1
}
init(start: Int) {
self.counter = start
}
func next() -> Element? {
return self.counter < 0 ? nil : counter--
}
}
struct ReverseSequence: SequenceType {
var array: [T]
init (array: [T]) {
self.array = array
}
typealias Generator = ReverseGenerator
func generate() -> Generator {
return ReverseGenerator(array: array)
}
}
Sequence
let arr = [0,1,2,3,4]
//對(duì)SequenceType可以使用for...in來(lái)循環(huán)訪問(wèn)
for i in ReverseSequence(array: arr) {
print("Index \(i) is \(arr[i])")
}
3.@autoclosure:把一句表達(dá)式自動(dòng)地封裝成一個(gè)閉包(closure)作用是使其清晰
注意:@autoclosure并不支持帶有輸入?yún)?shù)的寫法,也就是說(shuō)只有形如() -> T的參數(shù)才能使用這個(gè)特性進(jìn)行簡(jiǎn)化
func logIfTrue(predicate: () -> Bool) {}
func logIfTrue(@autoclosure predicate: () -> Bool) {}
??:var currentLevel = level ?? startLevel level是否為nil是取右邊否則取左邊
4.字面量轉(zhuǎn)換(通過(guò)結(jié)構(gòu)體基本數(shù)據(jù)類型生成對(duì)象)
所謂字面量,就是指像特定的數(shù)字,字符串或者是布爾值這樣,能夠直接了當(dāng)?shù)刂赋鲎约旱念愋筒樽兞窟M(jìn)行賦值的值
例如Person類String賦值來(lái)生成Person對(duì)象的話
Person類實(shí)現(xiàn)StringLiteralConvertible協(xié)議后可以直接初始化對(duì)象
let p: Person = "xiaoMing"
一.需要實(shí)現(xiàn)以下協(xié)議
? ArrayLiteralConvertible
? BooleanLiteralConvertible
? DictionaryLiteralConvertible
? FloatLiteralConvertible
? NilLiteralConvertible
? IntegerLiteralConvertible
? StringLiteralConvertible
class Person: StringLiteralConvertible {
//typealias StringLiteralType
typealias StringLiteralType = String
let name: StringLiteralType
init(name value: String) {
self.name = value
}
required convenience init(stringLiteral value: String) {
self.init(name:value)
}
required convenience init(extendedGraphemeClusterLiteral value: String) {
self.init(name:value)
}
required convenience init(unicodeScalarLiteral value: String) {
self.init(name:value)
}
}
func testPerson(){
let p : Person = Person(stringLiteral: "zzq")
print(p.name)
//直接通過(guò)string可以初始化對(duì)象
let p2 :Person = "ccc"
print(p2.name)
}
//在Swift中自定義下標(biāo)(subscript)可以給類結(jié)構(gòu)體(基本數(shù)據(jù)是結(jié)構(gòu)體)定義下標(biāo)[]
extension Int {
//定義下標(biāo)是Int類型
subscript(digitIndex: Int) -> Int {
var decimalBase = 1
for _ in 1...digitIndex {
decimalBase *= 10
}
return self * decimalBase * 2
}
}
class DailyMeal{
enum MealTime{
case Breakfast
case Lunch
case Dinner
}
var meals: [MealTime : String] = [:]
//定義下標(biāo)是MealTime類型
subscript(requestedMeal : MealTime) -> String{
get{
if let thisMeal = meals[requestedMeal]{
return thisMeal
}else{
return "Ramen"
}
}
//只讀下標(biāo)下面則省略神州省略get
set(newMealName){
meals[requestedMeal] = newMealName
}
}
}
func testSubscript(){
let a:Int = 123
print("i love \(a),\(a[5])")
var monday = DailyMeal()
monday[.Lunch] = "Pizza"
print(monday[.Lunch])//Output:"Pizza"
print(monday[.Dinner])//Output:"Ramen"
}
5.實(shí)例方法的動(dòng)態(tài)調(diào)用
class MyClass {
func method(number: Int) -> Int {
return number + 1
}
class func come(){
print("class fun")
}
//注意!當(dāng)存在和實(shí)例方法相同名的方法時(shí)候默認(rèn)通過(guò)類名點(diǎn)方法生成的是類方法的柯里化方法所以此時(shí)加類型參數(shù)區(qū)分
class func method(number: Int) -> Int {
return number
}
//區(qū)分如下:
/*這種方式不僅在這里有效,在其他大多數(shù)名字有歧義的情況下,都能很好地解決問(wèn)題
let f1 = MyClass.method // class func method的版本(由于實(shí)例和類方法相同名所以默認(rèn)是類方法)
let f2: Int -> Int = MyClass.method //和f1相同(所以定義Int->Int是默認(rèn)類方法)
let f3: MyClass -> Int -> Int = MyClass.method // func method的柯里化版本實(shí)例方法
*/
}
func testMyClass(){
//f:MyClass -> (Int) -> Int通過(guò)類名點(diǎn)方法生成一個(gè)可以"柯里化"的方法
let f = MyClass.method// MyClass.come()注意和類方法調(diào)用是不同的勿混淆
//實(shí)例化對(duì)象
let object = MyClass()
//調(diào)用方法
let result:Int = f(object)(1)
print(result)
}
6.命名空間
通過(guò)框架framework.類名調(diào)用不同的類以區(qū)分相同命名的類
通過(guò)結(jié)構(gòu)體名.類名或者類名.類名區(qū)分相同命名的類
7.Any和AnyObject
AnyObject(是個(gè)協(xié)議protocol)可以代表任何class類型的實(shí)例
Any(protocol<>)可以表示任意類型,甚至包括方法(func)類型
對(duì)于OC返回id類型擇對(duì)于swift返回->AnyObject?
所有的class都隱式地實(shí)現(xiàn)了這個(gè)接口AnyObject接口
protocol<>:需要實(shí)現(xiàn)空接口的接口”,其實(shí)就是任意類型的意思了葵袭。
8.typedef(OC)和typealias(swift)
有點(diǎn)特殊在swift中typealias對(duì)接口定義一個(gè)必須實(shí)現(xiàn)的別名涵妥。比如在GeneratorType和SequenceType這兩個(gè)接口中,Swift都用到了這個(gè)技巧
protocol GeneratorType {
typealias Element
mutating func next() -> Element?
}
9.@UIApplicationMain
swift不象Objective-C時(shí)那樣的main文件,也不存在main函數(shù)AppDelegate類的聲明上方有一個(gè)@UIApplicationMain的標(biāo)簽
10.初始化方法順序
與Objective-C不同,Swift的初始化方法需要保證類型的所有屬性都被初始化。所以初始化方法的調(diào)用順序就很有講究眶熬。在某個(gè)類的子類中,初始化方法里語(yǔ)句的順序并不是隨意的,我們需要保證在當(dāng)前子類實(shí)例的成員初始化完成后才能調(diào)用父類的初始化方法
class Cat {
var name: String
init() {
name = "cat"
}
}
class Tiger: Cat {
let power: Int
override init() {
power = 10
super.init()
name = "tiger"
}
}
一般來(lái)說(shuō),子類的初始化順序是:
1.設(shè)置子類自己需要初始化的參數(shù),power = 10
2.調(diào)用父類的相應(yīng)的初始化方法,super.init()
3.對(duì)父類中的需要改變的成員進(jìn)行設(shè)定,name = "tiger"
其中第三步是根據(jù)具體情況決定的,如果我們?cè)谧宇愔胁恍枰獙?duì)父類的成員做出改變的話,就不存在第3步妹笆。而在這種情況下,Swift會(huì)自動(dòng)地對(duì)父類的對(duì)應(yīng)init方法進(jìn)行調(diào)用,也就是說(shuō),第2步的super.init()也是可以不用寫的(但是實(shí)際上還是調(diào)用的,只不過(guò)是為了簡(jiǎn)便Swift幫我們完成了)块请。這種情況下的初始化方法看起來(lái)就很簡(jiǎn)單:
初始化方法順序
class Cat {
var name: String
init() {
name = "cat"
}
}
class Tiger: Cat {
let power: Int
override init() {
power = 10
}
//雖然我們沒(méi)有顯式地對(duì)super.init()進(jìn)行調(diào)用
//不過(guò)由于這是初始化的最后了,Swift替我們完成了
}
11. as?娜氏,as!,as墩新,is四者用法
as?:返回一個(gè)可選值贸弥,當(dāng)實(shí)例遵循協(xié)議時(shí),返回該協(xié)議類型海渊;否則返回nil
as!:用以強(qiáng)制向下轉(zhuǎn)換型绵疲,如子類實(shí)例父類引用時(shí)候該實(shí)例的向下轉(zhuǎn)型哲鸳,當(dāng)轉(zhuǎn)型失敗則報(bào)錯(cuò)異常。
as :將某實(shí)例(實(shí)現(xiàn)該協(xié)議)強(qiáng)轉(zhuǎn)為該協(xié)議調(diào)用協(xié)議的方法以此區(qū)分不同協(xié)議的同名方法
is :判斷某一個(gè)對(duì)象是否是某一個(gè)特定的類(OC isKindOfClass)盔憨。
12.static和class
static一般在struct和enum中使用可以修飾方法(靜態(tài)方法)存儲(chǔ)變量(靜態(tài)變量)和計(jì)算變量
class在class中可以修飾方法(類方法)計(jì)算變量徙菠,注意不能修飾存儲(chǔ)變量
注意:1.如果在類中要使用靜態(tài)變量只能使用static來(lái)修飾存儲(chǔ)變量
2.在class被static修飾的存儲(chǔ)變量,被class修飾計(jì)算變量郁岩,方法子類和父類都是公用的(OC也是如)
3.被class修飾的方法不能被子類重寫但是OC的類方法可以被子類重寫的
如果我們想在protocol里定義一個(gè)類型域上的方法或者計(jì)算屬性的話,應(yīng)該用哪個(gè)關(guān)鍵字呢?答案是使用class進(jìn)行定義
13.@objc和dynamic
在swift中對(duì)于非繼承NSObject類的在OC使用swift會(huì)因?yàn)镺C是運(yùn)行時(shí)機(jī)制{(KVC和動(dòng)態(tài)派發(fā)Dynamic)婿奔,在運(yùn)行時(shí)決定實(shí)際調(diào)用的具體實(shí)現(xiàn)},而找不到所需要的這些運(yùn)行時(shí)信息问慎,所以@objc關(guān)鍵字將類,屬性和方法暴露給OC萍摊。
注意:如果是繼承NSObject ,swift則會(huì)默認(rèn)自動(dòng)為所有的非private的類和成員加上@objc
添加@objc修飾符并不意味著這個(gè)方法或者屬性會(huì)變成動(dòng)態(tài)派發(fā),Swift依然可能會(huì)將其優(yōu)化為靜態(tài)調(diào)用。如果你需要和Objective-C里動(dòng)態(tài)調(diào)用時(shí)相同的運(yùn)行時(shí)特性的話,你需要使用的修飾符是dynamic如叼。一般情況下在做app開(kāi)發(fā)時(shí)應(yīng)該用不上,但是在施展一些像動(dòng)態(tài)替換方法或者運(yùn)行時(shí)再?zèng)Q定實(shí)現(xiàn)這樣的“黑魔法”的時(shí)候,我們就需要用到dynamic修飾符了冰木。
//需加上@objc來(lái)使用optional可選借接口方法實(shí)現(xiàn)否則swift的接口都必須實(shí)現(xiàn)所有的接口方法
@objc protocol OptionalProtocol {
optional func optionalMethod() //可選
func necessaryMethod() //必須optional func anotherOptionalMethod() //可選
}
14.內(nèi)存管理,weak和unowned
weak就是以前的weak,unowned更像以前的unsafe_unretained
class Person {
let name: String
//lazy var printName: ()->() = {
//print("The name is \(self.name)")
//}
//需改成以下[weak self]來(lái)避免閉包的循環(huán)引用
lazy var printName: ()->() = {
[weak self] in
if let strongSelf = self {
println("The name is \(strongSelf.name)")
}
}
init(personName: String) {
name = personName
}
deinit {
print("Person deinit \(self.name)")
}
}
func testFUN(){
let xiaoMing: Person = Person(personName: "XiaoMing")
xiaoMing.printName();
}
printName是self的屬性,會(huì)被self持有,而它本身又在閉包內(nèi)持有self,這導(dǎo)致了xiaoMing的deinit在自身超過(guò)作用域后還是沒(méi)有被調(diào)用,也就是沒(méi)有被釋放。為了解決這種閉包內(nèi)的循環(huán)引用,我們需要在閉包開(kāi)始的時(shí)候添加一個(gè)標(biāo)注,來(lái)表示這個(gè)閉包內(nèi)的某些要素應(yīng)該以何種特定的方式來(lái)使用笼恰。
如果我們可以確定在整個(gè)過(guò)程中self不會(huì)被釋放的話,我們可以將上面的weak改為unowned,這樣就不再需要strongSelf的判斷踊沸。但是如果在過(guò)程中self被釋放了而printName這個(gè)閉包沒(méi)有被釋放的話(比如生成Person后,某個(gè)外部變量持有了printName,隨后這個(gè)Persone對(duì)象被釋放了,但是printName已然存在并可能被調(diào)用),使用unowned將造成崩潰。在這里我們需要根據(jù)實(shí)際的需求來(lái)決定是使用weak還是unowned社证。
lazy懶加載
15.@autoreleasepool
16.值類型和引用類型
Swift中的struct和enum定義的類型是值類型,使用class定義的為引用類型雕沿。很有意思的是,Swift中的所有的內(nèi)建類型都是值類型,不僅包括了傳統(tǒng)意義像Int,Bool這些,甚至連String,Array以及Dictionary都是值類型的
在需要處理大量數(shù)據(jù)并且頻繁操作(增減)其中元素時(shí),選擇NSMutableArray和NSMutableDictionary會(huì)更好,而對(duì)于容器內(nèi)條目小而容器本身數(shù)目多的情況,應(yīng)該使用Swift語(yǔ)言內(nèi)建的Array和Dictionary。
17.Foundation框架
如果我們出于某種原因,確實(shí)需要NSString以及NSArray的話,我們需要顯式的轉(zhuǎn)換:
import Foundation
let string = "/var/controller_driver/secret_photo.png" as NSString
let fileName = components.lastObject as NSString
let fileName = components.lastObject as NSString
Swift的容器類型是可以裝任意其他類型的,包括各種enum和struct,而NSArray和NSDictionary只能放NSObject的子類對(duì)象猴仑。所以在Array和Dictionary中如果裝有非AnyObject或者不能轉(zhuǎn)為AnyObject的內(nèi)容的話,做強(qiáng)制的轉(zhuǎn)換將會(huì)拋出編譯錯(cuò)誤
18 lazy懶加載
//簡(jiǎn)單表達(dá)式
lazy var first = NSArray(objects: "1","2")
//閉包
lazy var name:String = {
return "second"
}()
//不要忘記最后的小括號(hào)审轮,只有加了小括號(hào),閉包才會(huì)在掉用的時(shí)候立刻執(zhí)行辽俗。
19.(指針)UnsafePointer
Swift定義了一套指針的訪問(wèn)和轉(zhuǎn)換方法,那就是UnsafePointer和它的一系列變體疾渣。對(duì)于使用C API時(shí)如果遇到接受內(nèi)存地址作為參數(shù),或者返回是內(nèi)存地址的情況,在Swift里會(huì)將它們轉(zhuǎn)為UnsafePointer的類型
void method(const int *num) { printf("%d",*num);}
其對(duì)應(yīng)的Swift方法應(yīng)該是:
func method(num: UnsafePointer) {
print(num.memory)//memory屬性讀取存儲(chǔ)的內(nèi)容C語(yǔ)言中使用*
}
var a: CInt = 123
method(&a)//取地址都是&
注意對(duì)于C語(yǔ)言的基本數(shù)據(jù)和swift區(qū)別是在前面加CCInt,CBool和CChar
C APIconst Type *Type *
Swift APIUnsafePointerUnsafeMutablePointer//可變指針
說(shuō)明:Swift不可變指針UnsafePointer ;可變指針UnsafeMutablePointer<>;
連續(xù)數(shù)據(jù)指針UnsafeBufferPointer;不透明指針COpaquePointer;方法指針CFunctionPointer
注意開(kāi)辟指針需要自己釋放
var pointer: UnsafeMutablePointer!
pointer = UnsafeMutablePointer.alloc(1)
pointer.initialize(MyClass())
println(pointer.memory.a)
pointer.destroy()
pointer.dealloc(1)
pointer = nil
malloc或者calloc開(kāi)辟的指針需要使用free而不是dealloc
//
func CFArrayGetValueAtIndex(theArray: CFArray!, idx: CFIndex)->UnsafePointer{
}
20 ...和..<
for i in 0...3 { print(i) }
let test = "helLo"
let interval = "a"..."z"
for c in test {
if !interval.contains(String(c)) {
println("\(c)不是小寫字母")
}
}
21.獲取對(duì)象類型
OC:
NSDate *date = [NSDate date]; NSLog(@"%@",NSStringFromClass([date class])); //輸出:__NSDate
[date class]與([NSDate class]區(qū)別輸出:NSDate)
Swift:
let date = NSDate()
let name = NSStringFromClass(date.dynamicType)//結(jié)果__NSDate
//注意與下面區(qū)別
NSStringFromClass(NSDate.self)//結(jié)果NSDate
不能使用NSStringFromClass(NSDate.class)
在OC中使用
NSStringFromClass(NSDate.class) NSStringFromClass(NSDate.self)
注意:對(duì)于String結(jié)構(gòu)體類型的無(wú)法使用上面的方法因?yàn)闆](méi)有實(shí)現(xiàn)AnyObject接口
這里使用_stdlib_getTypeName和_stdlib_getDemangledTypeName?崖飘?
22.AnyClass,元類型和.self
.self :.self可以用在類型后面取得類型本身,也可以用在某個(gè)實(shí)例后面取得這個(gè)實(shí)例本身
.Type :.Type表示的是某個(gè)類型的元類型
class A {
static var name: String = "zzzq"
class func testMethod(){
print("hello")
}
}
let typeA: A.Type = A.self//獲得是該元類只能調(diào)用類方法或者靜態(tài)屬性
typeA.testMethod()
print(typeA.name)
.Type表示的是某個(gè)類型的元類型,而在Swift中,除了class,struct和enum這三個(gè)類型外,我們還可以定義protocol榴捡。對(duì)于protocol來(lái)說(shuō),有時(shí)候我們也會(huì)想取得接口的元類型。這時(shí)我們可以在某個(gè)protocol的名字后面使用.Protocol來(lái)獲取,使用的方法和.Type是類似的
元類(metaclass):就是類對(duì)象不是實(shí)例對(duì)象
OC中:isa,實(shí)例對(duì)象的isa指向該類(存儲(chǔ)實(shí)例方法和實(shí)例變量)該類的isa指向元類(存儲(chǔ)類方法和靜態(tài)變量)
23.接口和類方法中的Self L
//定義接口返回接口的定義時(shí)
在OC中接口寫返回是instancetype類型來(lái)返回自己在swift中使用Self
protocol Copyable {
//應(yīng)該做的是創(chuàng)建一個(gè)和接受這個(gè)方法的對(duì)象同樣的東西,然后將其返回,返回的類型不應(yīng)該發(fā)生改變,所以寫為Self朱浴。然后開(kāi)始嘗試實(shí)現(xiàn)一個(gè)MyClass來(lái)滿足這個(gè)接口:
func copy() -> Self
}
class CopyClass: Copyable {
var num = 1
func copy()-> Self{
/*錯(cuò)誤代碼=> let result = MyClass() result.num = num return result*/
//正確如下
let result = self.dynamicType.init()
return result
}
/* required關(guān)鍵字修飾的初始化方法
這是因?yàn)镾wift必須保證當(dāng)前類和其子類都能響應(yīng)這個(gè)init方法*/
required init() {
}
}
24.自省
OC :
[obj1 isKindOfClass:[ClassA class]];
[obj2 isMemberOfClass:[ClassB class]];
swift :前提是NSObject子類
obj1.isKindOfClass(ClassA.self)
obj2.isMemberOfClass(ClassA.self)
使用is在功能上相當(dāng)于原來(lái)的isKindOfClass
class,struct或enum類型都可以使用is判斷
注意:編譯器將對(duì)這種檢查進(jìn)行必要性的判斷:如果編譯器能夠唯一確定類型,那么is的判斷就沒(méi)有必要,編譯器將會(huì)拋出一個(gè)錯(cuò)誤
25.動(dòng)態(tài)類型和多方法
Swift中我們雖然可以通過(guò)dynamicType來(lái)獲取一個(gè)對(duì)象的動(dòng)態(tài)類型(也就是運(yùn)行時(shí)的實(shí)際類型,而非代碼指定或編譯器看到的類型)但是在使用中,Swift現(xiàn)在卻是不支持多方法的,也就是說(shuō),不能根據(jù)對(duì)象在動(dòng)態(tài)時(shí)的類型進(jìn)行合適的重載方法調(diào)用吊圾。
OC在同類中是不支持同名不同參數(shù)的重載但是在swift中是支持
26.局部
在OC中使用{}將代碼局部區(qū)分局部有限
self.titleLabel = ({
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(150, 30, 20, 40)];
label.textColor = [UIColor redColor];
label.text = @"Title";
[view addSubview:label];
label;
});
swift中使用()
let titleLabel:UILabel = {
let label = UILabel(frame: CGRectMake(150, 30, 20, 40))
label.textColor = UIColor.redColor()
label.text = "Title"
self.view.addSubview(label)
return label
}()
對(duì)于OC使用{}局部區(qū)分swift自定義local方法
func local(closure: ()->()) {
closure()
}
local {
let titleLabel = UILabel(frame: CGRectMake(150, 30, 20, 40))
titleLabel.textColor = UIColor.redColor()
titleLabel.text = "Title"
}
27.Printable (2.0被CustomStringConvertible取代)和DebugPrintable (2.0被CustomDebugStringConvertible)
Swift中,大多數(shù)基礎(chǔ)對(duì)象都遵循了CustomStringConvertible協(xié)議翰蠢,比如Array项乒、Dictionary(Swift 1.0中的Printable協(xié)議),該協(xié)議定義了description方法梁沧,用于print方法打印對(duì)象
通過(guò)extension擴(kuò)展CustomStringConvertible實(shí)現(xiàn)description
28.訪問(wèn)級(jí)別
1.public:可以訪問(wèn)自己模塊或應(yīng)用中源文件里的任何實(shí)體檀何,別人也可以訪問(wèn)引入該模塊中源文件里的所有實(shí)體。通常情況下,某個(gè)接口或Framework是可以被任何人使用時(shí)频鉴,你可以將其設(shè)置為public級(jí)別栓辜。
2.internal(默認(rèn)級(jí)別):可以訪問(wèn)自己模塊或應(yīng)用中源文件里的任何實(shí)體,但是別人不能訪問(wèn)該模塊中源文件里的實(shí)體垛孔。通常情況下藕甩,某個(gè)接口或Framework作為內(nèi)部結(jié)構(gòu)使用時(shí),你可以將其設(shè)置為internal級(jí)別周荐。
3.private:只能在當(dāng)前源文件中使用的實(shí)體辛萍,稱為私有實(shí)體。使用private級(jí)別羡藐,可以用作隱藏某些功能的實(shí)現(xiàn)細(xì)節(jié)贩毕。
注意:1.Framework的內(nèi)部實(shí)現(xiàn)細(xì)節(jié)依然可以使用默認(rèn)的internal級(jí)別,或者也可以定義為private級(jí)別仆嗦。只有你想將它作為API的實(shí)體辉阶,才將其定義為public級(jí)別。
2.一個(gè)public類的所有成員的訪問(wèn)級(jí)別默認(rèn)為internal級(jí)別瘩扼。
3.元組的訪問(wèn)級(jí)別遵循它里面元組中最低級(jí)的訪問(wèn)級(jí)別谆甜。
4.枚舉中成員的訪問(wèn)級(jí)別繼承自該枚舉。public enum CompassPoint {}該類型public前定義集绰。
5.子類的訪問(wèn)級(jí)別不得高于父類的訪問(wèn)級(jí)別规辱。比如說(shuō),父類的訪問(wèn)級(jí)別是internal栽燕,子類的訪問(wèn)級(jí)別就不能聲明為public罕袋。
29.判等Equatable協(xié)議
swift中使用==判斷字符串內(nèi)容是否相同默認(rèn)字符串實(shí)現(xiàn)Equatable協(xié)議可以重寫該協(xié)議改變
注意這個(gè)協(xié)議在func == (lhs: String, rhs: String) -> Bool無(wú)需在實(shí)現(xiàn)協(xié)議中寫應(yīng)該放在全局
對(duì)于==的實(shí)現(xiàn)我們并沒(méi)有像實(shí)現(xiàn)其他一些接口一樣將其放在對(duì)應(yīng)的extension里,而是放在了全局的scope中。這是合理的做法,因?yàn)槟銘?yīng)該需要在全局范圍內(nèi)都能使用==碍岔。事實(shí)上,Swift的操作符都是全局的,關(guān)于操作符的更多信息,可以參看操作符浴讯。
class TodoItem {
let uuid: String
var title: String
init(uuid: String, title: String) {
self.uuid = uuid
self.title = title
}
}
extension TodoItem: Equatable {
}
//比較兩個(gè)對(duì)象
func == (lhs: TodoItem, rhs: TodoItem) -> Bool {
return lhs.uuid == rhs.uuid
}
//比較字符串
func == (lhs: String, rhs: String) -> Bool {
return true
}
補(bǔ):操作符(自定義運(yùn)算符)支持重載操作符這樣的特性
func +* (left: Vector2D, right: Vector2D) -> Double {
return left.x * right.x + left.y * right.y
}
注意:重載操作符時(shí)操作符是不能定義在局部域中的
要新加操作符的話,需要先對(duì)其進(jìn)行聲明,告訴編譯器這個(gè)符號(hào)其實(shí)是一個(gè)操作符。添加如下代碼
結(jié)合性(associativity)的值默認(rèn)為none(left蔼啦,right和none)榆纽,優(yōu)先級(jí)(precedence)默認(rèn)為100。
表達(dá):左結(jié)合的left捏肢,優(yōu)先級(jí)為140 :associativity left precedence 140
infix operator +* {
associativity none precedence 160
}
infix
表示要定義的是一個(gè)中位操作符,即前后都是輸入;其他的修飾子還包括prefix和postfix,不再贅述;
associativity
定義了結(jié)合律,即如果多個(gè)同類的操作符順序出現(xiàn)的計(jì)算順序奈籽。比如常見(jiàn)的加法和減法都是left,就是說(shuō)多個(gè)加法同時(shí)出現(xiàn)時(shí)按照從左往右的順序計(jì)算(因?yàn)榧臃M足交換律,所以這個(gè)順序無(wú)所謂,但是減法的話計(jì)算順序就很重要了)。點(diǎn)乘的結(jié)果是一個(gè)Double,不再會(huì)和其他點(diǎn)乘結(jié)合使用,所以這里寫成none;
precedence
運(yùn)算的優(yōu)先級(jí),越高的話越優(yōu)先進(jìn)行運(yùn)算鸵赫。Swift中乘法和除法的優(yōu)先級(jí)是150,加法和減法是140,這里我們定義點(diǎn)積優(yōu)先級(jí)160,就是說(shuō)應(yīng)該早于普通的乘除進(jìn)行運(yùn)算衣屏。
注意:Swift中對(duì)NSObject子類對(duì)象使用==時(shí)要是該子類沒(méi)有實(shí)現(xiàn)這個(gè)操作符重載的話將回滾到-isEqual:方法
30.哈希Hashable協(xié)議
在Objective-C中NSObject中有一個(gè)-hash方法。當(dāng)我們對(duì)一個(gè)NSObject的子類的-isEqual:進(jìn)行重寫的時(shí)候,我們一般也需要將-hash方法重寫奉瘤。
在Swift中,NSObject也默認(rèn)就實(shí)現(xiàn)了Hashable,而且和判等的時(shí)候情況類似,NSObject對(duì)象的hashValue屬性的訪問(wèn)將返回其對(duì)應(yīng)的-hash的值勾拉。對(duì)于非NSObject的類,我們需要遵守Hashable并根據(jù)==操作符的內(nèi)容給出哈希算法;而對(duì)于NSObject子類,需要根據(jù)是否需要在Objective-C中訪問(wèn)而選擇合適的重寫方式,去實(shí)現(xiàn)Hashable的hashValue或者直接重寫NSObject的-hash方法
31.斷言
注意:斷言只會(huì)在Debug環(huán)境中有效,而在Release編譯中所有的斷言都將被禁用
/*當(dāng)條件滿足條件的時(shí)候break同時(shí)打印出自己的定義內(nèi)容*/
assert(name == "zzqS", "it is zzq")
//OC中都是宏
/*當(dāng)條件滿足條件的時(shí)候break*/
assert(YES)
/*當(dāng)條件不滿足條件的時(shí)候break同時(shí)打印出自己的定義內(nèi)容*/
NSAssert(NO, @"Unimplemented JSBadgeAligment type %@", @break");
32.fatalError
@noreturn:不再需要返回值
@noreturn func fatalError(message: StaticString,file: StaticString = default,line: UWord = default)
fatalError(@"遇到我會(huì)強(qiáng)制退出程序...")
在父類方法中寫調(diào)用fatalError("這個(gè)方法必須在子類中被重寫")子類重寫覆蓋該方法則不會(huì)調(diào)用父類fatalError方法
//父類標(biāo)明了某個(gè)init方法是required的,但是你的子類永遠(yuǎn)不會(huì)使用這個(gè)方法來(lái)初始化時(shí),就可以采用類似的方式,被廣泛使用(以被廣泛討厭的) init(coder: NSCoder)就是一個(gè)例子
required init(coder: NSCoder) {
fatalError("NSCoding not supported")
}
32.final:final關(guān)鍵字可以用在class,func或者var前面進(jìn)行修飾,表示不允許對(duì)該內(nèi)容進(jìn)行繼承或者重寫操作
33.Swizzle
OC:
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method originalSelector = class_getInstanceMethod([UIButton class], @selector(sendAction:to:forEvent:));
Method swizzledSelector = class_getInstanceMethod([UIButton class], @selector(xxx_sendAction:to:forEvent:));
method_exchangeImplementations(originalSelector, swizzledSelector);
});
}
swift使用黑魔法替換UIButton的點(diǎn)擊事件統(tǒng)計(jì)所有按鈕被點(diǎn)擊數(shù)目
extension UIButton {
class func xxx_swizzleSendAction() {
struct xxx_swizzleToken {
static var onceToken : dispatch_once_t = 0
}
dispatch_once(&xxx_swizzleToken.onceToken) {
let cls: AnyClass! = UIButton.self
let originalSelector = Selector("sendAction:to:forEvent:")
let swizzledSelector = Selector("xxx_sendAction:to:forEvent:")
let originalMethod =
class_getInstanceMethod(cls, originalSelector)
let swizzledMethod =
class_getInstanceMethod(cls, swizzledSelector)
method_exchangeImplementations(originalMethod, swizzledMethod)
}
}
public func xxx_sendAction(action: Selector,
to: AnyObject!,
forEvent: UIEvent!)
{
struct xxx_buttonTapCounter {
static var count: Int = 0
}
xxx_buttonTapCounter.count += 1
print(xxx_buttonTapCounter.count)
xxx_sendAction(action, to: to, forEvent: forEvent)
}
}
注意:在Objective-C中我們一般在category的+load中完成,但是Swift的extension和Objective-C的category略有不同,extension并不是運(yùn)行時(shí)加載的,因此也沒(méi)有加載時(shí)候就會(huì)被調(diào)用的類似load的方法煮甥。另外,extension中也不應(yīng)該做方法重寫去覆蓋load (其實(shí)重寫也是無(wú)效的)最后我們看起來(lái)是在這個(gè)方法中調(diào)用了自己,似乎會(huì)形成一個(gè)死循環(huán)盗温。但是因?yàn)槲覀儗?shí)際上已經(jīng)交換了sendAction:to:forEvent:和xxx_sendAction:to:forEvent:的實(shí)現(xiàn),所以在做這個(gè)調(diào)用時(shí)恰好調(diào)用到的是原來(lái)的那個(gè)方法的實(shí)現(xiàn)藕赞。同理,在外部使用sendAction:to:forEvent:的時(shí)候(也就是點(diǎn)擊按鈕的時(shí)候),實(shí)際調(diào)用的實(shí)現(xiàn)會(huì)是我們?cè)谶@里定義的帶有計(jì)數(shù)器累加的實(shí)現(xiàn)
class Swizzler: NSObject {
override class func initialize() {
var onceToken : dispatch_once_t = 0;
dispatch_once(&onceToken) {
UIButton.xxx_swizzleSendAction()
}
}
}
Swizzle使用了Objective-C的動(dòng)態(tài)派發(fā),對(duì)于NSObject的子類是可以直接使用的,但是對(duì)于Swift的類,因?yàn)槟J(rèn)并沒(méi)有使用Objective-C運(yùn)行時(shí),因此也沒(méi)有動(dòng)態(tài)派發(fā)的方法列表,所以如果要Swizzle的是Swift類型的方法的話,我們需要將原方法和替換方法都加上dynamic標(biāo)記,以指明它們需要使用動(dòng)態(tài)派發(fā)機(jī)制。關(guān)于這方面的知識(shí),可以參看@objc和dynamic的內(nèi)容
34.lazy修飾符和lazy方法:
Swift中我們使用在變量屬性前加lazy關(guān)鍵字的方式來(lái)簡(jiǎn)單地指定延時(shí)加載
class ClassA {
lazy var str: String = {
let str = "Hello"
print("只在首次訪問(wèn)輸出")
return str
}() //注意有個(gè)()
}
簡(jiǎn)化:lazy var str: String = "Hello"
注意:1.只能聲明屬性是變量2.顯式地指定屬性類型
35.性能
在Objective-C對(duì)于NSObject的方法調(diào)用在編譯是會(huì)被轉(zhuǎn)為objc_megSend方法卖局。運(yùn)用OC運(yùn)行時(shí)特性,使用動(dòng)態(tài)派發(fā)的方式在運(yùn)行時(shí)對(duì)方法進(jìn)行查找斧蜕。
個(gè)人認(rèn)為最為靠近實(shí)際使用的標(biāo)志性特性就是它的消息機(jī)制了,能到比較容易的做到很多靜態(tài)語(yǔ)言很難做到的事情. Objective-C簡(jiǎn)單的運(yùn)行時(shí)知識(shí):
1.類和對(duì)象都是id,在給你一個(gè)id的前提下無(wú)法直觀的知道這個(gè)對(duì)象是類對(duì)象還是類本身.簡(jiǎn)單的可以簡(jiǎn)化成runtime管理的都是id (id的本質(zhì)其實(shí)是objc_object, objc_class頭部其實(shí)就是id,也就是isa).
2. Class在objc中是動(dòng)態(tài)創(chuàng)建的, selector, method, imp, protocol等都是隨后綁定上去的(即所謂的運(yùn)行時(shí)綁定).
3.通過(guò)runtime能夠查出當(dāng)前運(yùn)行時(shí)環(huán)境中所有的類,每個(gè)類中的方法,每個(gè)類消息的綁定,每個(gè)類的實(shí)現(xiàn)的協(xié)議,每個(gè)協(xié)議的定義,每個(gè)類當(dāng)前的消息緩存等一切你想知道的東西.
4.類的方法(消息)調(diào)用是間接的.
swift(靜態(tài)語(yǔ)言)和objective-c(具有動(dòng)態(tài)特性的靜態(tài)語(yǔ)言)都是(編譯語(yǔ)言)編譯執(zhí)行砚偶,swift比objective-c快的原因是批销,objective-c的方法是在運(yùn)行時(shí)確定函數(shù)地址,編譯時(shí)只記錄方法名,運(yùn)行時(shí)調(diào)用方法是根據(jù)方法名從哈希表中查找函數(shù)地址并跳躍到該地址執(zhí)行代碼,函數(shù)訪問(wèn)機(jī)制類似于C++的虛函數(shù),大量時(shí)間浪費(fèi)到查表上了。而swift的函數(shù)是在編譯時(shí)確定函數(shù)地址侨颈,運(yùn)行中直接跳躍到函數(shù)地址執(zhí)行,無(wú)須查表芯义,所以速度比objective-c快
但是swift使用繼承NSObjct的類是具有動(dòng)態(tài)特性的
36.Log輸出
FILE String包含這個(gè)符號(hào)的文件的路徑
LINE Int符號(hào)出現(xiàn)處的行號(hào)
COLUMN Int符號(hào)出現(xiàn)處的列
FUNCTION String包含這個(gè)符號(hào)的方法名字
func printLog(message: T,file: String = __FILE__,method: String = __FUNCTION__, line: Int = __LINE__){
print("\(file.lastPathComponent)[\(line)], \(method): \(message)")
}
37.Associated Object
swift中使用
private var key: Void
extension Class {
var title: String? {
get {
return objc_getAssociatedObject(self, &key) as? String
}
set {
objc_setAssociatedObject(self,&key, newValue,
.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
38.@asmname
無(wú)需通過(guò)c的h文件和-Bridging-Header.h文件導(dǎo)入C函數(shù)
@asmname("testCFun") funcctestCFun() -> Void
ctestCFun()直接調(diào)用
39.sizeofValue替換sizeof
sizeofValue(String)