1.Swift 中的属性必须默认有值,要不然就设置可空? ,否则编译不过
2.能不写self就不写,但是闭包里面要写,因为不知道何时执行这个闭包
3.懒加载,lazy关键字 ,闭包后面已经要加上() 。必须是var, swift 中的懒加载和oc中的懒加载不同,不会因为 置值为nil操作而执行懒加载中闭包。也就是说,懒加载 无论在什么情况下都是最多只执行一次。
4.如果闭包用于懒加载,那么包括in 之前的括号什么的可以省略,因为懒加载没有闭包的输入参数,并且可以推断返回类型
lazy var dataSource:[String] = {
print("加载")
return ["23","34","45","56"]
}()
5.出现switch condition evaluates to a constant 吧变量放到函数外面
不支持++ , -- 等运算符,但是 -= ,+= 还是支持的
swift3 。函数inout 用于修饰参数类型,而不是修饰参数,位置放到参数双引号之后,类型之前
6.可选类型 ;var name:String? = "tom" name是可选类型,可以是String,可以是nil (nil本身也是一种类型),如果name不是可选类型,那么name = nil 编译失败
可选类型是不能直接使用的,因为不知道什么时候变成nil,有可能导致crash。如果可选类型在使用的时候不解包,最明显的特征就是log会有option字样,解包之后就不会出现
1⃣️强制解包,不安全,使用前提 name!,使用前提必须确定name不会是nil,如果name是nil,强制解包会crash
2⃣️判空解包 if name != nil {print(name!)} 使用规则,在非空的作用域内使用name的时候,也是要强制解包的 +!
3⃣️可选链式调用,p.name = p.name!.uppercaseString 如果p.name是nil ,那么crash
p.name = p.name?.uppercaseString ✅,如果没有p.name 是nil ,那么直接返回nil。
可选链式 p.property1?.property2?.property3?....,一层层解包,只要有任意一个节点是nil。立刻返回nil
4⃣️空合运算符 作用解包之后,把解包之后的值赋值另外一个变量let name = p.name ?? "noname"
7.结构体, 结构体可有属性和函数,var myStruct = MyStruct() 结构体中的函数默认对属性没有写权限,mutating fun setPoitn ... mutating 关键字,函数对属性有写权限。
结构体中,计算属性不具备存储功能,所以不能给计算属性赋值
只读计算属性,必须是var
var length:Double{
return 22
}
如果结构体内部的函数对结构体属性进行修改,或者结构体对象直接对结构体属性进行修改,那么创建结构体对象的时候使用var
8.类可使用class static 修饰类方法,结构体只能使用static, 结构体会自动创建包涵所有存储属性的构造方法,类不会。
9 swift 中array dic string 结构体 都是值类型,使用== != 进行比较 ,class是引用类型,用=== !==进行比较。
10. 结构体:若函数被static修饰,是结构体的类型,否则结构体对象,
class ,若在类方法中,是当前类的类型,否则类的对象。
枚举体:即使类型,又是对象,看使用环境
11 .重写set 和 get方法 ,如果值重写了get方法,那么就是只读属性
12. 属性监听
13 给btn添加事件,不能priva
14 // swift 自定义协议,必须遵守NSObjectProtocol
protocol MyDelegate :NSObjectProtocol {
func didLogin()
}
否则,会编译失败
同时一定要吧delegate设置weak
weak var delegate:MyDelegate?
swift 通过代理响应方法不需要想oc一样判断有没有代理对象,和该对象是否响应协议方法,因为swift有可选链
delegate?.didLogin()
swift设置代理,该类必须要遵守这个代理,实现代理中必须要实现的方法
15.函数名和雷鸣冲突,会编译失败“use of undeclared type”
16.添加手势响应事件,按钮的响应事件,不能设置为private http://www.cocoachina.com/swift/20151023/13627.html
17. weak must be a mutable variable ,because it may change at runtime
18. 如果协议中使用到optional ,那么该协议必须加@objc修饰,
@objc protocol ToVCDelegate:NSObjectProtocol {
func must(num:Int)
@objc optional func choose(num:Int) //(swift 3 方法前➕@objc )
}
19 变量在创建的时候,要吗直接复制,要吗设置为可控类型, 直接复制也不能直接置nil.(下面是错误的)
let str:String
str = nil
print(str?.isEmpty)
20 swift 类型安全,对于数组,字典这种包涵子元素的类型数据,要吗直接给定子元素类型,要吗系统可以推断出子元素类型
let arr = Array() //没有给定Array子元素的类型,也没有Array子元素,所以无法推断出子元素类型,编译失败
// 编译失败:Generic parameter 'Element' could not be inferred
所以正确的做法这样
let arr:[String] = Array()
21;string(数组,字典。。也一样) oc中使用的foundation 框架的NSString, NSStiring是一个类,引用类型,传递的是指针,swift中的String 是结构体,传递给一个函数。方法。变量的时候,都是先复制,传递的是副本,二者地址是不一样的,不是同一个东西, 而Foundation框架的NSString ,传递的是指针,二者地址是一样的,还是同一个东西
var str = "abc"
var str2 = str
print("\(unsafeAddressOf(str)) \n \(unsafeAddressOf(str2))")
22:再懒加载的闭包里面访问成员变量,必须要self. 所有的闭包都是?
23.计算属性,get set ,如果不重写set ,那么该属性就是只读属性,对于只读的计算属性,也只能用var声明
24 结构体和枚举都是值类型,默认情况下,值类型的实例方法不能改变该实例的存储属性,使用mutating修改值类型的实例方法,使其变成可变方法,即可修改改实例的存储属性
struct Rectangle {
var width: Double
var height: Double
mutating func moveByX(x: Double, y: Double) {
width += x
height += y
}
}
⚠️ 不可变实例(let)不能调用可变方法。
25.程序对下标赋值时,swfit九转为调用对应的set部分代码,至于该set部分是否真正的完成,swift并不关心;程序访问下标,swfit转为调用对应的get部分代码,至于该get部分代码到底之行了什么,swift并不关心,只要该get部分最终返回一个类型匹配的值即可。
26:static : 在枚举、结构体、类中修饰属性、方法,将它们变成类型属性、类型方法
class: 在类中修饰属性、方法,将它们变成类型属性、类型方法。
使用static 修改的类型属性、类型方法不能被子类重写,使用class修饰的类型属性和类型方法可以被子类重写,
使用static修饰属性属性、方法,相当于同时使用class 和final。
27:方法类型定义变量
var myFunc: (() -> ())? // 最外层的()不能少
func hh() {
print("方法复制")
}
p.myFunc = hh
p.myFunc?()
28.闭包类型定义变量
var myClosure: ((Int) -> ())? // 最外层的()不能少
let closure = {(a: Int) -> Void in
print(a)
}
p.myClosure = closure
p.myClosure?(4)
29.在Swift中,要创建对象有以下几种方式:
1、NSString.self()// 或者NSString.self.init()
2、let myClass = MyClass.Type.init()
3、let myClass = MyClass.self.init()
4、let type = NSClassFromString("MyClass") as! MyClass.Type然后通过type.init()来创建对象
30: 类方法
类方法中self 表示的xxx.type 必须实现init方法之后,调用self.init() 即为创建对象
类方法没有实际的存储空间,不能被继承/重写
class func modelWithJson(json: [String : AnyObject]) -> AnyObject{
let obj = self.init()
obj.setValuesForKeysWithDictionary(json)
return obj
}
required override init() {
super.init()
}
31 不能扩展构造方法
32 构造器的坑和原则
如果重写直接父类制定构造器,还是使用override 修饰。比如Qubic_User: NSObject 那么Qubic_User在重写init的时候需要使用override修饰。
比如:GatewayCell: UITableViewCell 重写init的时候不需要使用override修饰,因为init是UIVIew的,重写init(style,reuse )的时候需要加上override。因为GatewayCell对象的直接父类是UITableViewCell
指定构造器总是必须向上代理(调用父类的构造器(如果有直接父类),不能调用便利构造器)
便利构造器总是必须横向代理(调用当前类的其它构造器,但是终点必须是指定构造器)
一旦子类自定义了指定构造器,那么就不会从父类继承任何指定构造器
33 private 的属性在扩展里面不能访问,
34.final修饰的方法不能被重写,修饰的属性和方法还是可以继承的
35.扩展出来的属性是可以被继承和重写的
36.扩展类属性static
extension Person {
@nonobjc static var info: String = "abc"
}
如果不加@noneObjc ,编译失败,a declaration cannot be both 'final' and 'dynamic'。
@noneObjc 作用
This issue arises because Swift is trying to generate a dynamic accessor for the static property for Obj-C compatibility, since the class inherits from NSObject.
If your project is in Swift only, rather than using a var accessor you can avoid the issue via the @nonobjc attribute in Swift 2.0:
37.Any :可代表任何类型,Int,Double等值类型 和 类的实例 var data:[String : Any] = [:]
AnyObject:可代表任何类的实例, var data:[String : AnyObject] = [:] value: 不能放值类型数据
38扩展终结
39,闭包的循环解决方,weak self (弱引用) 和 [unowned me] (无主引用)
二者区别: 无主引用不允许接收nil(即必须始终有值),因此无主引用只能定义非可选类型
若闭包和捕捉的实例总是相互引用,且同时销毁,宜采用无主引用,
若闭包捕获的引用变量可能是nil的时候,将闭包捕获的引变量定义为弱引用,弱引用必须是可选类型,当被引用的实例被销毁后,弱引用的变量会自动被赋值为nil,利用这个特性,程序可以在闭包内检查捕获的引用变量所引用的对象是否已经被回收
40. 延迟工作
let delayTime = DispatchTime.now() + 10
DispatchQueue.main.asyncAfter(deadline: delayTime) { // choose now or global
// dowork
}
41.map flat降维原理
对于n维数组,flattop比map 多了一个result.append(contentsOf:) 将它们的数组中的内容添加到结果集中,而不是数组本身 操作
42.通过setValuesForKeys(son) 给模型赋值的时候,必须保证json对应key的value 和 模型对应属性类型相同,否则crash
Raytimer
/*属性*/
var timers: [String: [RayTimerCMD]] = [:]
json
jsonTemp["timers"] = [] //[]crash [:]succeed
43.在扩展MBProgressHUD 的时候,欲设全局shareHUD,并且使用runtime绑定属性view,
忽略细节:对uiview进行了copy ❌
OBJC_ASSOCIATION_COPY_NONATOMIC ❌
OBJC_ASSOCIATION_COPY_NONATOMIC ✅
(最后考虑,这种扩展思路不行,hud显示的view得不到及时的释放)
44 @objc 和dynamic swift是否有动态性
@objc
找到官方文档读读。
可以知道@objc是用来将Swift的API导出给Objective-C和Objective-C runtime使用的,如果你的类继承自Objective-c的类(如NSObject)将会自动被编译器插入@objc标识。
我们在把TestASwiftClass(纯Swift类)的方法、属性前都加个@objc 试试,如图:
dynamic
文档里还有一句说明:
加了@objc标识的方法、属性无法保证都会被运行时调用,因为Swift会做静态优化。要想完全被动态调用,必须使用dynamic修饰。使用dynamic修饰将会隐式的加上@objc标识。
这也就解释了为什么testReturnVoidWithaId无法被替换,因为写在Swift里的代码直接被编译优化成静态调用了。
而viewDidAppear是继承Objective-C类获得的方法,本身就被修饰为dynamic,所以能被动态替换。
45.willSet 和 didSet 可以监听属性的变化,比如给cell的model赋值,属性类型包括(可选,!,默认值)
而不是重写属性的get set 方法(这是计算属性特有标志)
46:swift 使用cocoa pods
use_frameworks! # Add this if you are targeting iOS 8+ or using Swift
pod 'CocoaAsyncSocket'
47.swift3废弃dispatch_once, 被替换成全局懒加载。
48.let distance = distance(toPoint: byPoint) 等号两边一样,编译错误: “variable used within its own initial value”
49
50: 闭包可以访问和修改其所在上下文中的常量和变量(常量只能修改,不能访问),这个过程被称为捕获,即使定义这些常量或变量的作用域已经不存在了,闭包依然可以访问或者修改他们, 闭包是引用类型dede
如果闭包没有没强引用,执行完之后,就没了,也就丢弃了其所持有的对象