1、随机数
不需要随机数种子
arc4random()%N + begin:产生begin~begin+N的随机数
arc4random_uniform(endIndex-startIndex)+startIndex:产生startIndex到endIndex的随机数
arc4random_uniform(N):产生0~N-1之间的随机数
2、自动闭包;??操作符如何实现
1)闭包
闭包标准定义
{[捕获列表] (参数) ->返回类型in语句returnxxx}
//自动闭包,闭包标准定义
testClusure { (s, s2) -> String in
return "1"
}
//根据上下文:推断类型,推断类型指的是1)返回类型,2)参数类型
testClusure() {
s1, s2in
return "123"
}
//单表达式:隐式返回,表达式的值作为返回值
testClusure { s1, s2 in
"asdfasdfadsf"
}
//参数名称缩写
testClusure {
$0 + $1
}
testClusure(clusure: +)
//尾随闭包省略括号()
testClusure { (s1, s2)in
returns1 + s2
}
2)自动闭包
不接受任何参数!!
表达式的值,会被返回
//自动闭包
testClusureAuto(adsf:"asdfasdfasdf")
func testClusureAuto(adsf clusure:@autoclosure () -> String) {
}
省略花括号,用一个普通的表达式来代替显示的闭包
表达式、语句
自动闭包的意义:延迟求值
??
&&
||
()->T
T
如果我们直接使用T,意味着??操作符取值之前,我们就必须准备好一个默认值传入到这个方法中。
如果这个值是经过一系列的复杂运算,就会造成浪费,因为如果optinal值是有值的,根本就用不上T这个默认值
而是直接返回解包后的值。
这样的开销是可以完全避免的,就是将默认值的计算推迟到判断optional为nil之后
逃逸
@escaping
闭包
值捕获
引用类型,值类型
let playClosure = {
(child:Child) -> ()? in
child.Pet?.toy?.play()
}
func play() {
}
if let a:() =playClosure(xiaoming) {
}
let playClosure = {
(child:Child) -> String? in
child.Pet?.toy?.play()
}
func play() -> String {
return "adsf"
}
if let a =playClosure(xiaoming) {
}
child.Pet?.toy?.play()单表达式闭包隐式返回,整个表达式的值作为闭包的返回值
就看play的定义了
这样的调用将会返回一个()?
其实就是一个可选的空元组:猫神也不是万能的啊,这都说不明白:“虽然看起来挺奇怪的,但这就是事实”
3、操作符
1、重载操作符
2、声明一个新的操作符
定义一个操作符的优先级
结合律方式,优先级顺序
操作符不能定义在局部域中,要求能在全局返回使用你的操作符
adjacent operators are in non-associativeprecedence group tt
adjacent相邻
associative组合
precedence优先级
struct Developer{
static func test() {
let t1 = Developer()
let t2:Developer = "a"
let t3 = "helloooooo"
let _ = t1~=t2~=t3
}
}
//字面量表达
extensionDeveloper:ExpressibleByUnicodeScalarLiteral{
typealias UnicodeScalarLiteralType = String
init(unicodeScalarLiteral value: String) {
logFlag("我就啥也不干")
}
}
//操作符重载
precedencegroup tt {
//指定结合性
associativity:left
//指定优先级
higherThan:MultiplicationPrecedence
}
infix operator ~=:tt
func~=(left:Developer,right:Any)->Developer{
print("我给Developer类实现了一个自定义的操作符:~=,有需要用的吗?")
return left
}
//不指定优先级和结合性也可以重写啊
infix operator ~+
func ~+(left:Developer,right:Developer){
print("我就啥也不干,就看看操作符是这些重写吗")
}
4、inout
&:
inout原理:inout,修改变量。在函数内部创建了一个新的值,并把这个值赋值给原来的变量
值类型:
inout在函数内部,创建了一个新的值,然后在函数返回的时候,把这个值符给了给&修饰的变量,
这与引用类型的inout机制是不同的。
如果是引用类型呢??
5、字面量表达
字面量表达-》字面量表达协议-》协议规定了哪些方法??
一个类型支持字面量表达赋值,则需要自定义一个相关类型的表达协议,并把这个类型继承他
自定义一个自己的字面量表达
隐式转换,使用字面量的方式进行
let a = "asdfasdfafsd"//这就是字符串字面量
let a =
["asdfafsd","asdfasdf"]//数组字面量
let a =
["a":"asdfasdf","b":"1231321"]//字典字面量
把一个类型,实现ExpressionByBooleanLiteral系列的协议,这个类就支持字面量表达了
字面量表达很隐蔽的特性。缺点是,没有办法对字面量复制进行跳转。我们不知道这个赋值到底是在哪里实现的
6、下标
重写下标操作符
7、嵌套
函数嵌套
8、命名空间
默认是使用自己所在的target的.编译系统会根据不同的targe自动加上命名空间。
如果在同一个target里面,如果定义的某个类是相通的,还是会产生冲突
app:
第三方framework:
myframework.myclass
9,typealias
别名
场景1
class df{
}
//typealias dff = df
typealias dff =df
场景2--组合协议
protocol Pro1{}
protocol Pro2{}
typealias Proall = Pro1 & Pro2
10、associatedtype:关联类型
1)
协议中声明一个关联类型,在协议中规定的属性、方法中使用这个关联类型
当某个类、结构体、枚举约定为继承这个协议时,
在实现这个协议规定的方法中,可以对协议规定的关联类型进行指定,
这样在实现这些协议方法、属性时,不同的类、结构体、枚举,虽然继承同样一个协议,
但是,操作的结果就不一样的,不需要对类型进行is as? as!方法进行类型判断!
2)有associatedtype的协议,不能单独使用
protocol animal can only be used as ageneric constraint
because it has self or associated type
requirements
protocol Animal{
associatedtype F
func eat(food:F)
}
struct Tigger:Animal{
typealias F = Meat
func eat(food: Meat) {
print("老虎吃肉")
}
}
protocol Animal2{
func eatFood()
}
extension Animal2{
func eatFood(){
}
}
struct Chicekent:Animal2{}
struct Dogg:Animal2{}
func isDangerous(animal:Animal2)->Bool {
if animal is Dogg {
return true
}else {
return false
}
}
//func isDangerous(animal:Animal)->Bool {
//if animal is Tiger {
//return true
//} else {
//return false
//}
//}
11,可变参数
只能有有一个参数是可变的
可变参数的类型都是相同的,但是可以用Any
12,init,deinit顺序
init先子类,再父类
deinit先子类,再父类
super.init可以不用写的,系统会自动加上,如果要修改父类的值,则需要显示调用super.init,然后在访问父类的变量,进行修改。
要在init中调用init,需要在init前面加convenience
父类中带参数的init在子类中重载时,子类的这个init实现中系统不会自动加,需要手动添加
父类的便利构造器,子类调用父类便利构造器实现的init方法,子类不需要写便利构造器,同样可以获得便利构造器的使用
13,optional init
求x的y次方pow
14,class,static
1)非class类型,struct,enum:使用static
2)class专门用在class类型中,如果用static,表示不可以重写
3)协议中使用static
至于为什么?
class可以重写,static不可以重写
struct,enum值类型的数据类型中,可变存储属性,常量存储属性,计算属性,方法类属性,类方法都是子类不可以重写的,因此用static
struct,enum值类型不允许实现子类,就不存在重写的问题,所用static,表示不可以重写
struct,enum不允许继承:inheritancefrom non-protocol type 'StructA1'
协议中规定的属性,方法,也是不可以在子协议中进行重写的,因此用static
class类中用class类属性:只能是计算属性,可以用class,static
protocol协议中,加static,类属性、类方法
struct A1{
func printHello(){}
}
//struct A2:A1 {
//func printHello(){}
//}
class ClassA1{
func printHello(){}
class func printHello2(){}
static func printHello3(){}
static var s1:String = "123"
class var s2:String {get{return "123"}}
static let s3:String = "1212"
}
class ClassB1:ClassA1{
override func printHello(){}
override class func printHello2(){}
//override static func printHello3(){}
}
protocol ProtocolA1 {
static func printHello()
static var s3:String{get}
//class func printHello2()
//protocol协议,实例属性可以实现为计算型,也可以实现为存储型
var s4:String{get}
var s5:String{get set}
var s6:String{get}
}
class ClassA2:ProtocolA1{
static func printHello() {
}
static var s3: String {return "asdfasf"}
var s6: String {return "asdfasd232"}
var s4: String = {return "asdfasdfa"}()
var s5: String = "1234123"
}
15、集合
1)Dictionary,array,set类型都是相同的,或者都为any
2)如何实现一个多类型集合呢?巧用枚举来实现,存储多种不同类型的值
枚举关联值
class func testAnyCollection(){
let a =[strOrInt.getInt(123),strOrInt.getStr("asdfa"), strOrInt.getBlock({(hell) in
print(hell)
})]
for i in a {
switch i {
case .getBlock(let a):
a("1341234123")
case .getStr(let s):
print(s)
case .getInt(let n):
print(n)
//case .getIntAndStr(let s, let n):
//print(s)
//print(n)
case .getIntAndStr(let s, 1):
print(s)
case .getIntAndStr(let s, let a):
print(s, a)
}
}
}
enum strOrInt{
case getStr(String)
case getInt(Int)
case getBlock((String)->())
case getIntAndStr(String,Int)
}
16、正则表达式
如何构建一个正则表达式工具
这个工具用一个struct来组织
1)提供pattern变量,提供一个初始化方法,提供一个匹配方法
2)更高级一点的方法是:实现一个操作符,
func =~(left:String, right:String) ->Bool {
}
17、模式匹配
switch,for,if,try..catch..,
1)判等
2)判可选类型是否为nil
3)判范围
底层如何实现的呢?
其实就是系统实现了~=操作符。
18、...和..<
其实这就是range操作符
这个操作符,系统有一系列的操作符范型函数的定义
...start<=end
..
range操作符返回一个:范型闭开区间或者范型range
HalfOpenInterval
Range
ClosedInterval
应用场景:
1)for语句
2)先创建一个闭开或者range,然后使用闭开或者range的coutains方法,判断某个字符是否属于这个闭开区间。
比如判断是不是小写字母
19、.self,和.Type
AnyClass
.Type存放类型的类型
有Int类型:存放的是整形值,String类型:存放的是字符串,AnyObject.Type类型存放的是Anyobject类型
ClassA.self:类型实例
一个存放类型的类型,怎么称呼他?元类型
意义:
调用类方法:调用类方法的时候可以用这个元类型的实例来调用它的类方法
.self类型实例
.Type类型实例的类型
.self协议实例
.Protocol协议类型实例的类型
//协议元类型,有啥作用呢
let s11:ProtocolA1.Protocol = ProtocolA1.self
//用法1,用模式匹配
//很明显:系统没有实现这种类型的模式匹配操作~=,那我们来一个
let e:[Any.Type] =[NSString.self,NSDictionary.self,NSArray.self,ClassA3.self,String.self,(()->()).self]
for i in e {
switch i {
case NSString.self:
print("这里存放了一个nsstring类型,把这个类型存起来了")
case String.self:
print("string类型")
case (()->()).self:
print("得了")
default:
print("asdfa")
}
}
func ~=(left:Any.Type,right:Any.Type)->Bool{
if left == right {
return true
}
return false
}
//用法2,用if语句
let arr:[AnyObject.Type] = [ClassA3.self,ClassA1.self]
for i in arr {
if i is ClassA1.Type {
letd = i as! ClassA1.Type
d.printHello2()
}
if i == ClassA3.self {
let d = i as! ClassA3.Type
d.print2()
}
}
20、Self
copy方法举例
//定义个一个协议:使用Self
protocol Copyable{
func copy()->Self
}
class MyClass:Copyable{
func copy()->Self{
let r = type(of:self).init()
return r
}
required init(){
}
}
21、动态类型
多方法
swift,编译器编译的时候,决定使用哪个方法;swift默认情况下,不采用动态派发。
方法的调用在编译的时候决定。
如果不要系统自动派发,可以修改代码,用as?类型进行判决,调用对应类型的方法
22、属性观察器
1)willset,didset存储型属性可以加,计算型属性不允许加观察器。
因为计算型属性,本来就可以监控到属性的改变
2)如果偏要给已有的类型增加观察器,怎么操作?
用子类来继承。继承了以后,给父类的任何属性:存储型,计算型都可以加观察器,我们不用管他是
存储型还是计算型。
3)唯一注意点是什么:
正因为子类重写父类的计算型属性的观察器,didset方法会先读oldvalue,这将导致父类的get方法被调用。
23、什么情况下使用final
1)md5算法、des加密解密的工具类,很稳定了,可以加final。
2)某些类似编号的产生方法等对系统的正确运行决定作用的属性或方法,加final,防止子类重写时给系统造成错误
3)加了final,子类不能去做一些自己可以做的事情,怎么破解呢?
我们可以在final的这个方法中,调用一个方法,并在当前类定义中实现这个方法,在这个方法断言,子类必须去重写。
这样,就解除了我们在调用final方法过程中不能做一些自己想做的事情。
class ClassB3:ClassB2{
override func getConfigValue() -> String {
return "come from b3 class !!"
}
}
class ClassB2{
final func printHello(){
print("load begin")
let a = getConfigValue()
print("load end"+a)
}
func getConfigValue()->String{
fatalError("子类必须要实现这个方法")
}
}
24、lazy
延迟属性、延迟方法
1)延迟,相比于oc,延迟存储属性,延迟计算属性
延迟存储变量,延迟计算变量
2)如果没有猫神,确实我仅知道1的应用场景
swift提供了几个全局方法
//序列: lazy方法名,范型列表,参数:范型参数,符合协议SequenceType的一个实例,返回一个LazySequence范型类实例
func lazy(s:S) ->LazySequence
//无序
func lazy(s:S) ->LazyRandomAccessCollection
//双向
func lazy(s:S) ->
LazyBidrectionCollection
//前向
func lazy(s:S)->LazyForwardCollection
给一个集合,返回一个集合
这个比较难
arr.lazy.map
25、swift运行时
反射和mirror
class func testRuntime(){
let a = PersonA(name: "asdf", age: 12)
let mirror = Mirror(reflecting: a) // MirrorType
for child in mirror.children {
print(child.label , child.value)
}
}
class PersonA{
var name:String
var age:Int
init(name:String,age:Int){
self.name = name
self.age = age
}
}
应用场景:
1)在运行的时候,通过Mirror的手段,了解一个Swift类型的实例的属性信息
我们可以把某一个swift实例,通过mirror,得到children,
label,value集合值,找到我们要找的目标key value
2)局限:swift的mirror只能读取,不能修改。我们最好不要在app中用这个mirror,
而是在playground和repl中对类的层次进行探索
26、隐式解包
可选类型
?
!
Optional
1)可选类型,是什么类型??
是结构体,枚举,类,闭包,元组,函数?
当然是枚举
enum Optional {
//啥也没有
case None
//关联类型:关联一个T类型的实例
case Some(T)
}
2)
多重Optional是个什么鬼?
这样理解,
var a:String? = nil
let b:String?? = a盒子?盒子?放了一个字符串
let c:String?? = nil盒子?空盒子or不是空盒子
3)Optional Map
extension CollectionType {
//入參:一个闭包: 1)参数是采纳本身这个协议的一个element实例2)返回值是返回一个任意类型
//返回值:返回一个任意类型的数组
publicfunc map (transform:@noescape ((Self.Generator.Element) -> T))-> [T]{
//Swift标准库具体的实现
}
}
public enum Optinal:_Reflectable,NilLiteralConvertible {
//入參:一个闭包:1)参数是一个任意类型,2)返回值是任意类型的这么一个闭包
//返回值:任意类型
publicfunc map(f:@noescape((T)->U))-> U? {
//Swift标准库实现
}
}
Int?=>Optional
String? =>Optional
Array? => Optional
函数式编程的思想,他是一种思想,写一个函数,约定一个规则,在这个规则下写这个函数,不要乱搞。
我们因此又称他为范式。
函数式编程的范式又是什么呢?
1,函数是第一等公民
2,只用表达式,不用语句
表达式:单纯的运算过程。总是有返回值
语句:执行某种操作,没有返回值
函数式编程的出发点动机,就是处理运算。
3,没有副作用
函数内部与外部互动,产生表达式运算以外的结果。
函数式编程强调:函数要保持独立,
所有功能就是返回一个新的值,没有其他的行为,尤其是不得修改外部变量的值。
4,不修改状态
变量往往用来保存“状态”,不修改变量,意味着状态不能保存在变量中。
函数式编程使用参数保存状态的一个特例就是递归。
5,引用透明
只要传入什么参数相同,返回的结果永远都是相同
Optional可选实例的map方法
结合类型的map方法
let arr= [1,2,3,4]
let arr2 = arr.map{$0 * 2}
print(arr2)
let b:Int? = 1
let c = b.map { t in return"12341"}
print(c)
27、协议扩展
应用场景:
1)提供一个协议方法的默认实现,=》变相实现了可选协议
2)如果一个协议的扩展中提供了一个默认实现,然后这个协议并没有对这个默认函数进行声明。
继承这协议的类的实例调用这个方法时,还是可以调这个默认实现的。如果这个类中自己实现了这个协议方法,他会调用自己类里面实现的。
这正是按照我们所想的方法执行的。
3)扩展一个协议的时候,加上where限定条件,可以指定1)、继承这个协议的2)并且满足条件的类、结构体、枚举Self,需要实现这个扩展
中的方法。
28,where在哪里使用
//报错:where clasuecannot be attached to a protocol declaration
protocol ProtoclA18 where Self:String {
func method2()
}
协议不能像class一样在名称后面加来定义范型,但是可以使用关联类型associated来定义一个引入的范型类型。
如何定义个一个协议,只能要求被某些特定类来实现呢??
//Perfect
定义一个空协议,然后扩展这个协议,在扩展中指定这个协议,只能由某些特定类型来继承
protocol ProtocolA18{
}
extension ProtocolA18 whereSelf:ProtocolOther{
func method()
}
@objc protocol ProtocolA18{
}
extension ProtocolA18 whereSelf:ProtocolA19 {
func method2(){}
}
extension ProtocolA18 where Self:ClassTest{
func method3(){}
}
protocol ProtocolA19 {
func method2()
}
@objc protocol ProtocolA17 {
func method()
}
//这个类不继承那个协议,交给它所属的实例类来实现协议
class ClassA17:ProtocolA18 {
//协议类型
weakvar protocolObj:ProtocolA18?
//method2, method3都不需要实现。
func method2(){
}
}
class ClassTest:ProtocolA18 {
var a:ClassA17!
func viewDidLoad(){
//let a = ClassA17()
a = ClassA17()
a.protocolObj = self
}
func method() {
print("helloworld")
}
deinit {
logFlag()
}
func method3() {
}
}
//if else
let arr = ["123413","胡asdf","胡阿水淀粉","李思思"]
arr.forEach { (a:String) in
if a.hasPrefix("胡") ,a.characters.count > 4 {
print(a ,"是老师")
}else {
print(a, "是学生")
}
}
//switch case
arr.forEach { (a) in
switch a {
//这where只能加一个条件啊
case let x where x.hasPrefix("胡"):
print(a ,"是老师")
default:
print(a, "是学生")
}
}
//for in
for i in arr where i.hasPrefix("胡") {
print(i ,"是老师")
}
//用在协议扩展里:扩展协议中,对扩展的协议增加限定:关联类型继承某个协议
let c2 = ClassC2()
let c1 = ClassC1()
c1.printBBB()
//报错
c2.printBBB()
extension ProtocolC1 whereSelf.TT:Comparable {
func printBBB(){
print("bbb")
}
}
extension ProtocolC1 {
//func printAAA()
func printhello(){
print("扩展协议,提供了方法的默认实现,但是这个方法,并没有在协议中定义")
}
}
class ClassC2:ProtocolC1{
var name="asdfasdf"
typealias TT = Any?
func printhello() {
print("AAA")
}
}
class ClassC1:ProtocolC1{
typealias TT = Int
var name = "asdfasf"
func printhello() {
print("我们自己来实现这个协议,那么扩展协议中的默认实现的方法还会被调用吗")
}
}
29、使用枚举而不是class或者struct来定义一个链表
不加indirect,编译报错!
嵌套定义枚举的时候,必须加上indirect关键字
class func testIndirectEnum(){
let a1 = E.n(1)
let a2 = E.n(3)
let a3 = E.add(a1, a2)
let r = E.eval(l: a3)
print(r)
}
indirect enum E {
case n(Int)
case add(E, E)
//需要一个嵌套函数
static func eval(l:E)->Int{
switch l {
case .n(let t):
return t
case .add(let l1, let l2):
returneval(l: l1) + eval(l: l2)
}
}
}
class C1{
classfunc a() {
let c = E.add(E.add(E.n(1), E.n(3)), E.n(3))
let d = E.eval(l: c)
print(d)
let _ = LinkedList.node(1, LinkedList.node(2, LinkedList.empty))
}
}
30, Swift -》》selector
2种表现形式Selector and#selector
selector是一个关键字,返回一个类型
-(void)callMe{}
SEL method = @selector(callMe)
-(void)callMe:(id)obj{}
SEL method2 = @selector(callMe:)
swift=>
定义一个selector
挂一个方法:@objc
class AA {
@objc func printhello(){}
func print(){
#selecotor(printhello)
}
}
@objc(BB)
class BB {
func printHello()
func print(){
#selecotor(printhello)
}
}
执行一个selector
Selector("method")警告:不要显示调用,需要改为#selector关键字
#selector(method(parm1:param2:))
#selector(method(param1:))
#selector(method2)
如果同名子的方法只有一个,没有参数、标签不同的同名函数,则可以省略参数列表
func method2(a:String,b:String){}
func method(param1:String,param2:String){}
func method(param1:String){}
#selector(method2)//这种调用也是可以的。因为他的方法没有同名
但是可以将方法进行强制转换
#selector(method as (string,string)->())
#selector(method as (string)->())
31,实例方法的动态调用
实例方法
实例属性不可以
class ClassA10{
func printHello(){
logFlag("hello")
}
}
//字面量取值
f = ClassA10.pringHello
{
//参数ClassA10
(obj:ClassA10) in
//返回值:是一个函数
return obj.printHello
}
f1(ClassA10())()
原理:
(Xcode8_swift3_iOS8_10.ClassA10)->()->()
(Xcode8_swift3_iOS8_10.ClassA10)->(String)->()
(Xcode8_swift3_iOS8_10.ClassA10)->(String,String)->(String)
(Xcode8_swift3_iOS8_10.ClassA10)->(String)->(String)
柯里化方法
(String)->()-()
//动态调用
let f1 = ClassA10.printHello
f1(ClassA10())()
//ClassA10.printHello的字面量表达
let a = {
(obj:ClassA10) -> ()->() in
return obj.printHello
}
a(ClassA10())()
32,单例
实例属性:存储型常量,存储型变量,计算型变量
类属性:存储型常量,存储型变量,计算型变量
由于swift1.2之前版本的属性特性,类属性不能有存储型变量、存储型常量。所以单例的实现方式就要借助于全局变量,
然后在计算型变量中,返回这个全局变量。
那么1.2开始以后,就会有更简单的单例实现版本了。
class Manager{
//存储型常量来保存单例
static let shared = Manager()
private init(){}
}
33,条件编译
1)条件的语法怎么写?
还是c语言语法格式的写法,只不过对条件加了指定
#if XXX
#elseif XXX
#else
#endif
//省略else,elseif
#if XXX
#endif
//省略elseif
#if XXXX
#else XXX
#endif
2)什么情况用到条件编译?
指定的条件如下:
os()
os(macOS) os(iOS) os(tvOS) os(watchOS)os(Linux)
os(FreeBSD) os(Windows) os(Android)
arch()
arch(x86_64)
arch(arm)
arch(arm64)
arch(i386)
swift()
swift(1.2)
swift(2.3)
swift(3.0)
#if FREE_VERSION
#else
#endif
build settings->swift compiler -》custom flags-》other swift
flags加上-D FREE_VERSION
34、Xcode标记
// MARK:
// MARK:-
// TODO:
// FIXME:
oc中有的:
#warning
#param
35、@UIApplicationMain
生成模版代码
36、
动态派发
@objc修饰
@dynamic
oc中的协议里存在关键字:
@optional
//swift不支持可选协议
protocol OptionalProtocol{
optional func optionalMethod()
}
//支持可选协议,
@objc protocol OptionalProtocol {
@objc optional func optionalMethod()
}
使用@objc修饰的协议,只能被class实现,不能被struct,enum实现
37、内存管理
引用计数
arc
当实例的引用为nil的时候,系统就会释放内存
什么时候实例的引用为nil?
1)超过作用域,2)手动设置为nil
产生循环引用的条件:
1)引用类型实例产生循环引用
2)闭包引起循环应用,其实闭包也是一个引用类型。还是可以归属为1
一个class有一个闭包属性。闭包属性里面又使用了self,就产生循环
在方法内部初始化的生成的对象在被返回后别人还能使用,而不是立即释放掉
延迟释放
func autoreleasepool(code:()->())
每次超过作用域后,自动内存管理都会为我们处理好内存相关的事情???
//每次获得一个产生一个data
func loadBigData() {
if let path =nsbundle.mainbundle().pathForResource("big",ofType:"jpg") {
for i in 1...10000 {
autoreleasepool{
//方法1:
let data =nsdata.datawithContentsOfFile(path,options:nil,error:nil)
//方法2:工厂方法-》》初始化方法
let data =NSData(contentsOfFile:path)
nsthread.sleepfortimeInterval(0.5)
}
}
}
}
整个线程一个自动释放池,每个主runloop结束时候进行drain操作。
drain的作用:
1)把池子里面的引用类型的实例,实例的引用为nil的时候,或者说引用计数为0的实例,进行释放。
所以,即使一个实例没有强引用了,或者引用计数为0了,只要释放池没有执行drain操作,他就不会得到释放
2)把引用计数-1
值类型
传递、赋值=》复制
引用类型
传递、赋值=》引用对象的一个指向
String,Dictionary,Array,值类型,少量数据用此。如果数据大,就用cocoa中的NSDictionary,NSArray
值类型:内存是在栈上。
引用类型:堆上。
String or NSString ?
//String
let a = "ABCDE"
let range =a.characters.index(a.startIndex, offsetBy:1)..
let b = a.replacingCharacters(in: range,with: "A")
print(b)
//NSString
let c = (a asNSString).replacingCharacters(in: NSMakeRange(1, 4), with: "A")
print(c)
38、Swift和C
Swift和C指针
Swift如何处理指针?
C的识别特点就是指针
OC -》C?
Swift-》C?
Unsafe开头的,
void * -》UnsafePoint
const Type * ->UnsafePointer
Type * ->UnsafeMutablePointer
unsafeBitCast(CFArrayGetValueAtIndex(arr,0),to:CFString.self)
C开头的;
int -》CInt
array -> CFArray
string -> CFString
COpaquePointer
UnsafeMutablePointer并不会自动进行内存管理,因此把某一个pointer = nil,并不能自动释放内存
deinitialize-》释放指针指向的内存的对象
deallocate -》释放指针自己本身
指向函数的指针-》C打交道,1)直接用闭包2)@convention(c)标注
allocate
initialize
deinitialize
deallocate
var a:UnsafeMutablePointer!
a =UnsafeMutablePointer.allocate(capacity: 1)
a.initialize(to: ClassA12())
print(a.pointee.name)
a.deinitialize()
a.deallocate(capacity: 1)
a = nil
opaquepointer
39、怎么封装一个漂亮的gcd调用?
嵌套函数好复杂!!!
40、Swift类型操作
1)获取类型的类型
xx.self和Type
类型,XXX.self
类型的类型,XXX.Type
AnyClass = AnyObject.Type
2)获取实例的类型
实例=》》》》类型
type(of:obj)
object_getClass(obj)
3)Self
class MyClass:Copyable {
funccopy()->Self {
letr = type(of:self).init()
returnr
}
requiredinit(){
}
}
4)swift类型判断
isKindOfClass:属于某个类或者继承自这个类
isMemberOfClass:属于某个类
适用于NSObject类型或其子类型
isKind
isMemeber
用is:is相当于原来的isKindOfClass,可以检查属于某个类或者继承自这个类
他不仅可以用class引用类型上,还可以用于struct,enum类型
在范型中使用类型判断:提前约束是何种类型,在编译期间就可以确定类型要求
41、花括号的演变
1、
c语言中利用{}
1)代码块,看着清晰一点
2)利用作用域,释放内存
2、
swift 2.0以前
用尾随闭包
func do(b:()-()){
b()
}
do{
。。。。。
}
3、
那么2.0以后呢?
就用do,加入了do关键字,捕获异常的作用区域
do {
}
4、
使用匿名闭包----用闭包赋初始化值
let label:UILabel = {return UILabel()}()
42、
swift判等
NSObject子类:看是否重写了父类isEqual方法,默认的是用父类的isEqual方法判等
Swift类型,不继承NSObject的类:判等==,需要把类继承Equatable协议,然后实现操作符==方法,否则编译报错
如果是Swift的原生类型,如String,Dictionary,系统自动实现了Equtable协议了,我们不需要自己去重写啥的。
let a1 = ClassA13(name: "huchu")
let a2 = ClassA13(name:"study")
if a1 == a2 {
print("重写的判断生效了")
}
let a3 = ClassA14(name: "huchu")
let a4 = ClassA14(name:"study")
//报错,无法编译:没有重写判断操作符==
if a3 == a4 {
print("无法判等的")
}
let a5 = ClassA15(name: "huchu")
let a6 = ClassA15(name: "study")
if a5 == a6 {
print("NSObject的子类,默认调用NSObject父类的判等方法:isEqual")
}
let a7 = ClassA16(name: "huchu")
let a8 = ClassA16(name: "study")
if a7 == a8 {
}
class ClassA13:Equatable {
var name:String
init(name:String) {
self.name = name
}
public static func ==(lhs: ClassA13, rhs: ClassA13) -> Bool {
return true
}
}
class ClassA14 {
var name:String
init(name:String) {
self.name = name
}
}
class ClassA15:NSObject {
var name:String
init(name:String) {
self.name = name
}
}
//Redundant conformance of classa16 toprotocol equatable
class ClassA16:NSObject,Equatable {
var name:String
init(name:String) {
self.name = name
}
override func isEqual(_ object: Any?) -> Bool {
print("NSObject的子类,默认调用NSObject父类的判等方法:isEqual")
if object is ClassA16 {
let j = object as! ClassA16
return j.name == self.name
}
return false
}
public static func ==(lhs: ClassA16 , rhs: ClassA16) -> Bool {
print("NSObject的子类,优先看有没有实现Equatable协议方法==判等操作符:优先调用了")
if lhs.name == rhs.name {
return true
}
return false
}
}
43、swift日志输出
NSLog
占位:
%d,%@,%02d,%f
let t = String(format: "%.02f",b)
print(t)
print("\\(t)")
let t2 = String(format: "%.02f",1.234567)
print(t2)
print("\\(t2)")
let t3 = String(format: "%.02f",1234567)
print(t3)
print("\\(t3)")
NSLog("%.02f", 1234567)
NSLog("%.02f", 1234567.1)
输出如下
1.23
1.23
1.23
1.23
0.00
0.00
0.00
1234567.10
在oc中输出
NSLog(@"%.02f", 1234567);
0.00
44、Options选项
原来的选项Option值-》满足OptionSetType协议的struct类型,以及一组静态的get属性。
想一想,why?
OptionSetType是实现了SetAlgebraType的
Algebra:代数学
set algebra:集合代数
用集合来代替逻辑运算符&、|位运算
//这里太复杂:OptionSet
struct SexOptions : OptionSet {
//可以省略
typealias RawValue = UInt
let rawValue:UInt
static let none = SexOptions(rawValue: 0)
static let optionMale = SexOptions(rawValue: 1)
static let optionFemale = SexOptions(rawValue: 1<<1)
static let optionGmale = SexOptions(rawValue: 33)
}
public protocol OptionSet : SetAlgebra,RawRepresentable {
}
public protocol RawRepresentable {
}
public protocol SetAlgebra : Equatable,ExpressibleByArrayLiteral {
}
public protocol Equatable {}
public protocol ExpressibleByArrayLiteral{}
字面量。
45、列举
enumerate:列举元素的同时,也需要下标
// OC的用法
func addf() {
var arr:NSArray = [1,2,3,4,5,6]
var r = 0
//ambiguous use of enumerateObjects为什么报错?
arr.enumerateObjects { (value, idx, stop) -> Void in
r += num as! Int
if idx == 2 {
stop.pointee = true
}
}
print(r)
}
//Swift
var arr = [1,2,3,4,5,6]
func addfSwift() {
var r = 0
//没有要求在闭包中操作,我还想测试一下循环引用的
for (idx, value) in arr.enumerated() {
r += value
if idx == 2 {
break
}
}
print(r)
}
let arr = [(1,2),(3,4)]
for i in arr {
print(i.0, i.1)
}
for i in arr.enumerated() {
print(i.0,i.1)
}
for (a,b) in arr.enumerated() {
print(a, b.0,b.1)
}
输出如下:
1 2
3 4
0 (1, 2)
1 (3, 4)
0 1 2
1 3 4
EnumerateGenerator:包含元素索引下标,以及元素本身的多元组
EnumeratedSequence>
EnumeratedSequence分析:
EnumeratedSequence是一个结构体,范型结构体,范型要求为符合协议--Sequece协议
并且自身也符合协议--Sequece协议
怎么就跟元组挂上钩了呢???
难道又是模式匹配吗,又或是字面量表达
字面量表达-》字面量表达协议-》协议规定了哪些方法??
switch,for,if,try..catch..,
1)判等
2)判可选类型是否为nil
3)判范围
底层如何实现的呢?
其实就是系统实现了~=操作符。
[(1,2),(12,312),(1234,1234)]
确实是啊!!
public static func ~=(pattern:CountableClosedRange, value: Bound) -> Bool
Sequece协议规定了一个~=模式匹配的方法
EnumeratedSequence<[(Int,Int)]>
EnumeratedSequece<[Int]>
46、通过类型获取对应的编码?这又是个什么鬼
OC中的用法:
@encode
Swift中的用法:
Metatype
不能获取任意类型的类型编码了。
但是在Cocoa中,即继承自NSObject类型的类,可以通过NSValue的objcType来获取对应值的类型指针。
如果需要获取Swift类型的类型编码,可以将他转换为NSNumber,NSNbumer是NSValue的子类,然后再获取类型
objCType
let t1 = 1 as NSNumber
print(String(validatingUTF8: t1.objCType))
let t2 = NSValue(cgPoint:CGPoint(x: 3, y:3))
print(String(validatingUTF8: t2.objCType))
let t3 =NSValue(cgAffineTransform:.identity)
print(String(validatingUTF8:t3.objCType))
输出如下:
Optional("q")
Optional("{CGPoint=dd}")
Optional("{CGAffineTransform=dddddd}")
//这有个毛的意思?
Swift语言参考
类型、
Swift类型:string,dictionry,array,Int,Double。。。。
Swift中保留的C类型:CInt,CFArray....
Swift中保留的OC类型:NSDictionary...
函数类型,闭包类型,协议类型。。。。
表达式、
3+4, let a = 3 , somefunciton()
语句、
if else,
while,
for,
do{try...}catch模式1{}catch模式2{}catch {}
switch-case
模式匹配、
i in 1...10,
case模式
where Self:SomeProtocol
where i > 10
声明、
特性、
范型
47、@asmname使用c的标准库
48、weak
1)协议前面加上@objc
2)协议后面加上class
applied:应用
weak may only be applied to classand class-bound protocol types
protocol ProtocolA17 {
func method()
}
protocol ProtcolA18 where
//这个类不继承那个协议,交给它所属的实例类来实现协议
class ClassA17{
//协议类型,这是一个成员属性,这个属性必须要求实现协议
weak var protocolObj:ProtocolA17?
}
class ClassTest:ProtocolA17 {
var a:ClassA17!
func viewDidLoad(){
//let a = ClassA17()
a = ClassA17()
a.protocolObj = self
}
func method() {
print("helloworld")
}
deinit {
logFlag()
}
}
swift中的protocol协议:
值类型,引用类型都可以继承某一个协议,struct,enum虽然可以用protocol,但是不存在引用计数这样的内存管理问题,所以就无需用到weak
@objc protocol ProtocolA17 {
func method()
}
protocol ProtocolA20:class{
func method()
}
//这个类不继承那个协议,交给它所属的实例类来实现协议
class ClassA17:ProtocolA18 {
//协议类型
weak var protocolObj:ProtocolA18?
//method2, method3都不需要实现。
func method2(){
}
}
class ClassA20{
weak var obj:ProtocolA20?
}
class ClassTest:ProtocolA18,ProtocolA20 {
var a:ClassA17!
var b:ClassA20!
func viewDidLoad(){
//let a = ClassA17()
a = ClassA17()
a.protocolObj = self
b = ClassA20()
b.obj = self
}
func method() {
print("helloworld")
}
deinit {
logFlag()
}
func method3() {
}
}
49、关联对象
public struct UnsafeRawPointer :Strideable, Hashable {
}
static var key:Void?
&key=>>UnsafeRawPointer这样就可以转了吗?
//key这个参数,为什么是要传入一个可变的指针
public func objc_getAssociatedObject(_object: Any!, _ key: UnsafeRawPointer!) -> Any!
public func objc_setAssociatedObject(_object: Any!, _ key: UnsafeRawPointer!, _ value: Any!, _ policy: objc_AssociationPolicy)
extension ClassA20{
static var title:()?
static var key2 = "adfs"
static let key3 = "123123"
var title:String{
get{
return objc_getAssociatedObject(self, &ClassA20.title) as! String
}
set{
objc_setAssociatedObject(self, &ClassA20.title, newValue,objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
var title2:String{
get{
return objc_getAssociatedObject(self, &ClassA20.key2) as! String
}
set{
objc_setAssociatedObject(self, &ClassA20.key2, newValue,objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
//cannot pas immutable value as inout argument:key3 is a let constant
var title3:String{
get{
return objc_getAssociatedObject(self, &ClassA20.key3) as! String
}
set{
objc_setAssociatedObject(self, &ClassA20.key3, newValue,objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
let a = ClassA20()
print(ClassA20.key2)
print(ClassA20.title)
a.title = "hello"
a.title2 = "world"
print(ClassA20.key2)
print(ClassA20.title)
输出如下
adfs
nil
adfs
nil
50、线程同步
objc_sync_enter
objc_sync_exit
怎么在swift中在封装一下,更加好用?
class func lockSafe(lock:Any,l:()->()){
objc_sync_enter(lock)
l()
objc_sync_enter(lock)
}
class func testLock(){
let obj = ClassA20()
objc_sync_enter(obj)
print(obj)
objc_sync_exit(obj)
Test.lockSafe(lock: obj) {
print(obj)
}
}
59、CF*****Swift自带的CF系列,内存管理自动管理的。不需要release等
60、
swift命令
repl:swift repl环境read eval printloop
可以进行简单的交互式编程,每输入一句语句,就立即执行到我们眼前
xcrun swift
swift
如何写一个swift脚本,就像shell脚本一样?
vi 1.swift
#!/usr/bin/env swift
print("hello")
chmod +x 1.swift
./1.swift
swift文件如何编译
vi 2.swift
print("hello")
swiftc 2.swift 3.swift other.swift....
./main
swift生成汇编代码
vi 3.swift
print("hello")
swiftc -O 3.swift -o 3.asm
61、print和debugPrint
结论,
1)实现了custom和customdebug其中的任何一个,print,debugPring打印的都是一样的结果
2)如果都实现了,pring调用custom,debugPrint调用customDebug
3)如果都没有实现,那就只能系统默认打一个ClassX.self的类型了
print是执行CustomStringConvertible协议规定的方法
printDebug是执行CustomDebugStringConvertible协议规定的方法
对于一个普通的对象,只能打印出它的类型。
struct可以打印出成员的名称和值
如何实现一个CustomStringConvertible协议?
extension ClassA20:CustomStringConvertible{
var description: String {
return "helll"
}
}
extensionClassA20:CustomDebugStringConvertible {
var debugDescription: String {
return "world"
}
}
1)实现CustomStringConvertible,不实现CustomDebugStringConvertible:
helll
helll
2)不实现CustomStringConvertible,实现CustomDebugStringConvertible:
world
world
3)实现CustomStringConvertible,实现CustomDebugStringConvertible:
helll
world
4)不实现CustomStringConvertible,不实现CustomDebugStringConvertible:
Xcode8_swift3_ios8_10.ClassA20
Xcode8_swift3_ios8_10.ClassA20
print(ClassA20.self)
debugPrint(ClassA20.self)
输出
ClassA20
Xcode8_swift3_ios8_10.ClassA20
62、断言
断言:它是一个开发时的特性,只有在debug编译的时候有效。而在运行时是不能被编译执行的。
所以,在代码发布的时候,我们不用刻意去将这些断言手动清理掉。
这是默认的断言特性
target, build settings swift
compiler-custom flags中
other swift flags中添加
-assert-config Debug来强制启用断言,
-assert-config Release来强制禁用断言
貌似不管用啊!!!
在release中,如何强制终止程序呢,我们最好不要修改断言的配置选项。
而是使用另外一个函数。
fatalError
调用这个方法,不需要返回值
func asd()->Int{
fatalError("asdf")
}
断言只会在Debug环境中有效,而在Release编译中所有的断言都将被禁用。在遇到确实因为输入的错误无法使程序继续运行的时候,我们一般考虑以产生致命错误(fatalError)的方式来终止程序。
63、面向协议编程和模拟的抽象函数的方式
64、错误和异常
异常
1)为什么要用异常?
调用某些方法,我们开发时候很容易忽略的时候,就用异常,避免我们忽略nserror
同步调用中用异常
异步调用不用异常,用error
2)怎样使用异常
do try catch
try?
try!
throws
实现一个继承Error枚举的枚举类。抛出这个新的枚举类型。
class func someMethodTrhows2 (b:Bool)throws-> Int? {
if b {
throw myError.value
}
return nil
}
//返回的是nil还能执行if。因为是optional套一个optional
if let a = try?someMethodTrhows2(b: false){
print(a)
} else {
print("err")
}
rethrows :
在方法中加rethrows,表示这个方法的型參列表中,有一个参数,也可能抛出异常,即是一个能抛出异常的闭包类型或者函数类型,
然后呢,这个方法本身自己不会抛出任何异常,除了型參的方法被调用抛出异常外。
如果这个方法,仍然用throws来修饰:表明,型參闭包被调用时,抛出异常;自己的处理过程中,也允许抛出异常。
凡是调用了抛出异常的方法,在调用它时,都必须加上try的形式来调用。
这表明啊:加rethrows的方法,只要它的参数,我们给他传递进去的时候,虽然在型參中我们声明了这个函数可能抛出异常,但是
我们在实參的定义中,如果作为实參的闭包,并没有抛出异常,既没有写throw Error.XXX时,我们是可以不用try来调用的!!
既可以接受普通函数,也可以接受一个普通函数,虽然这个参数是throw的
//报错
someMethodTrhows1(b: true)
//报错
someMethodTrhows3(b:true) { (b) -> Int in
if b {throw myError.value}
}
//不报错,可以这样用
someMethodTrhows3(b: true) { (b) -> Intin
return 1
}
//必须要加try调用
try!someMethodTrhows4(b: true) { (b) ->Int in
return 100
}
a function declared rethrows may only throwif its parameter does
class func someMethodTrhows3(b:Bool,f:(Bool)throws->Int) rethrows-> Int {
let _ = try f(true)
//a function declared rethrows may only throw if its parameter does
//if b {
//throw myError.value
//}
return 100
}
class func someMethodTrhows4(b:Bool,f:(Bool)throws->Int) throws-> Int {
let _ = try f(true)
if b {
throw myError.value
}
return 100
}
let _ = try?someMethodTrhows3(b: true, f: {(b:Bool) -> Int in
if b {
throw myError.value
}
return 100
})
let _ = try?someMethodTrhows4(b: true, f: {(b:Bool) -> Int in
if b {
throw myError.value
}
return 100
})
65、framework orextension
框架or扩展?
1)单独为swift制作框架-》专门生成框架的项目
将整个框架项目,包括源代码,以项目依赖的方式添加到自己的项目中,并一起编译使用。
shift+cmd+i release版本
cmd+b debug版本
2)制作的框架只能嵌入到自己的app中
3)用纯Swift制作可用的第三方库
66、字符串=》使用原始值为String的enum类
然后通过扩展类的extension,来引用这些enum。
R.swift SwiftGen,扫描所有文件-》提取字符串-》自动生成enum或者struct文件
67、
@dynamic:告诉编译器,我们不会再编译时就确定这个属性的行为实现
不需要在编译期间对这个属性的getter或setter做检查和关心。
表示我们将在运行时来提供这个属性的存取方法,如果在运行时,没有对这个属性提供存取方法,就会crash
CoreDataModel,
使用xcode工具,自动生成NSManagedObject子类
Swift,不保证一切都走动态派发。
CoreData专用:@NSManaged
68、KVO、KVC
动态派发
观察的对象标记为dynamic
在oc中,KVC的属性,进行监听。而现在,需要NSObject的,dynamic修饰的,可以监听
Observable-Swift
范型、闭包、属性观察器-》》》KVO