目录
]
选择器的用法
//一、选择器的用法
func selectorUse() -> Void {
/**
选择器(Selector) n
wift中依然可以使用选择器,使用#selector(name)定义一个选择器
必须是被@objcMembers或@objc修饰的方法才可以定义选择器
*/
@objcMembers class Person: NSObject {
func test1(v1: Int) { print("test1: v1 is ",v1) }
func test2(v1: Int, v2: Int) { print("test2(v1:v2:)") }
func test2(_ v1: Double, _ v2: Double) { print("test2(_:_:)") }
func run() {
perform(#selector(test1))
perform(#selector(test1(v1:)))
perform(#selector(test1(v1:)),with: 5)
perform(#selector(test2(v1:v2:)))
perform(#selector(test2(_:_:)))
perform(#selector(test2 as (Double, Double) -> Void))
}
}
let person = Person()
person.run()
/**
test1: v1 is 4295577213
test1: v1 is 4295577213
test1: v1 is 6932140607943212441
test2(v1:v2:)
test2(_:_:)
test2(_:_:)
*/
}
string 的用法
//1、 空字符串
do{
print("------1-------")
//Swift的字符串类型String,跟OC的NSString,在API设计上还是有较大差异
let emptyStr1 = ""
let emptyStr2 = String()
print("emptyStr1:\(emptyStr1)","emptyStr2:\(emptyStr2)",separator:"|")
}
//2、字符串获取
do{
print("------3-----")
let str = "123456"
print(str.hasPrefix("123")) // true
print(str.hasSuffix("456")) // true
//str.startIndex 指向 0
print(str[str.startIndex])//1
//str.endIndex 指向 str.count
//print(str[str.endIndex])//error 越界
print(str[str.index(str.endIndex, offsetBy: -1)])//6
let str2 = "22334455"
print(str[str2.firstIndex(of: "4")!]) //5
print(str[str2.lastIndex(of: "4")!]) //6
}
//3、字符串拼接
do{
print("------2-----")
var str: String = "1"
// 拼接,jack_rose
str.append("_2")
print(str)//1_2
// 重载运算符 +
str = str + "_3"
print(str)//1_2_3
// 重载运算符 +=
str += "_4"
print(str)//1_2_3_4
// \()插值
str = "\(str)_5"
print(str)//1_2_3_4_5
print(str.count)//9
}
//4、字符串插入删除
do{
print("--------4---------")
var str = "1_2"
// 1_2_
str.insert("_", at: str.endIndex)
// 1_2_3_4
str.insert(contentsOf: "3_4", at: str.endIndex)
// 1666_2_3_4
str.insert(contentsOf: "666", at: str.index(after: str.startIndex))
// 1666_2_3_8884
str.insert(contentsOf: "888", at: str.index(before: str.endIndex))
// 1666hello_2_3_8884
str.insert(contentsOf: "hello", at: str.index(str.startIndex, offsetBy: 4))
// 666hello_2_3_8884
str.remove(at: str.firstIndex(of: "1")!)
// hello_2_3_8884
str.removeAll { $0 == "6" }
// hello_2_3_4
let range = str.index(str.endIndex, offsetBy: -4)..<str.index(before: str.endIndex)
str.removeSubrange(range)
}
//5、String 与 Character
do{
print("-------5--------")
for c in "jack" { // c是Character类型
print(c)
}
let str = "jack"
let c = str[str.startIndex]// c是Character类型
print("c is ", c)
}
//6、substring
do{
print("------6-------")
//String可以通过下标、 prefix、 suffix等截取子串,
//子串类型不是String,而是Substring
var str = "1_2_3_4_5"
let substr1 = str.prefix(3)
print(substr1)// 1_2
let substr2 = str.suffix(3)
print(substr2) // 4_5
let range = str.startIndex..<str.index(str.startIndex, offsetBy: 3)
let substr3 = str[range]
print(substr3) // 1_2
// 最初的String,
print(substr3.base)// 1_2_3_4_5
/**
Substring和它的base,共享字符串数据
Substring发生修改 或者 转为String时,会分配新的内存存储字符串数据
str的修改,也不会影响substr值
*/
// Substring -> String
let str2 = String(substr3)
print(str2) //1_2
str = "hello"
print(substr1)//1_2
print(substr1.base)//1_2_3_4_5
}
//7、String相关的协议
do{
/**
BidirectionalCollection 协议包含的部分内容
startIndex 、 endIndex 属性、
index 方法
String、Array 都遵守了这个协议
RangeReplaceableCollection 协议包含的部分内容
append、insert、remove 方法
String、Array 都遵守了这个协议
Dictionary、Set 也有实现上述协议中声明的一些方法,只是并没有遵守上述协议
*/
}
//8、多行String
do{
print("------8-------")
let str0 = """
1
"2"
3
'4'
"""
print(str0)
// 如果要显示3引号,至少转义1个引号
let str1 = """
Escaping the first quote \"""
Escaping two quotes \"\""
Escaping all three quotes \"\"\"
"""
print(str1)
// 以下2个字符串是等价的
let str2_1 = "These are the same."
let str2_2 = """
These are the same.
"""
print("str2_1:",str2_1)
print("str2_2:",str2_2)
// 缩进以结尾的3引号为对齐线
let str3 = """
1
2 3
4
"""
print(str3)
}
//9、String 与 NSString
do{
print("-------9---------")
/**
String 与 NSString 之间可以随时随地桥接转换
如果你觉得String的API过于复杂难用,可以考虑将String转为NSString
*/
let str1: String = "jack"
let str2: NSString = "rose"
let str3 = str1 as NSString
let str4 = str2 as String
print(str4)//rose
let str5 = str3.substring(with: NSRange(location: 0, length: 2))
print(str5)// ja
/**
比较字符串内容是否等价
String使用 == 运算符
NSString使用isEqual方法,也可以使用 == 运算符(本质还是调用了isEqual方法)
*/
}
}
String | ⇌ | NSString |
String | ← | NSMutableString |
Array | ⇌ | NSArray |
Array | ← | NSMutableArray |
Dictionary | ⇌ | NSDictionary |
Dictionary | ← | NSMutableDictionary |
Set | ⇌ | NSSet |
Set | ← | NSMutableSet |
可选协议
//三、可选协议
//1、只能被class继承的协议
//被 @objc 修饰的协议,还可以暴露给OC去遵守实现
protocol LCRunnable181: AnyObject {}
protocol LCRunnable182: class {}
@objc protocol LCRunnable183 {}
//2、可选协议
//可以通过 @objc 定义可选协议,这种协议只能被 class 遵守
@objc protocol LCRunnable184 {
func run1()
@objc optional func run2()
func run3()
}
func optionalProtocol() -> Void {
class Dog: LCRunnable184 {
func run3() { print("Dog run3") }
//func run2() -> Void {print("Dog run2")}//可以不实现
func run1() { print("Dog run1") }
}
let d = Dog()
d.run1() // Dog run1
d.run3() // Dog run3
}
dynamic
//四、dynamic
func dynamicUse() -> Void {
//被 @objc dynamic 修饰的内容会具有动态性,比如调用方法会走runtime那一套流程
class Dog: NSObject {
@objc dynamic func test1() {}
func test2() {}
}
let d = Dog()
d.test1()//objc_msgsend会走消息发送机制
d.test2()
}
kvc kvo
//五、 kvc kvo
func kvcKvoUse() -> Void {
/**
Swift 支持 KVC \ KVO 的条件
属性所在的类、监听器最终继承自 NSObject
用 @objc dynamic 修饰对应的属性
*/
//1、kvc kvo
do{
print("--------1--------")
class Observer: NSObject {
override func observeValue(forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?) {
print("observeValue new ", change?[.newKey] as Any)
print("observeValue old ", change?[.oldKey] as Any)
}
}
class Person: NSObject {
@objc dynamic var age: Int = 0
var observer: Observer = Observer()
override init() {
super.init()
self.addObserver(observer,
forKeyPath: "age",
options: [.new,.old],
context: nil)
}
deinit {
self.removeObserver(observer,
forKeyPath: "age")
}
}
let p = Person()
//observeValue new Optional(20)
//observeValue old Optional(0)
p.age = 20
//observeValue new Optional(25)
//observeValue old Optional(20)
p.setValue(25, forKey: "age")
}
//2、block方式的KVO
do{
print("--------2--------")
class Person: NSObject {
@objc dynamic var age: Int = 0
var observation: NSKeyValueObservation?
override init() {
super.init()
observation = observe(\Person.age, options: [.new,.old]) {
(person, change) in
print("person :",person)
print("newValue :",change.newValue as Any)
print("oldValue :",change.oldValue as Any)
}
}
}
let p = Person()
//person : <_TtCF20LCClientDemo_commond9kvcKvoUseFT_T_L0_6Person: 0x101806340>
//newValue : Optional(20)
//oldValue : Optional(0)
p.age = 20
//person : <_TtCF20LCClientDemo_commond9kvcKvoUseFT_T_L0_6Person: 0x101806340>
//newValue : Optional(25)
//oldValue : Optional(20)
p.setValue(25, forKey: "age")
}
}
关联对象(Associated Object)
//六、关联对象(Associated Object)
class LCPerson182 {}
extension LCPerson182 {
private static var AGE_KEY: Void?
var age: Int {
get {
(objc_getAssociatedObject(self, &Self.AGE_KEY) as? Int) ?? 0
}
set {
objc_setAssociatedObject(self, &Self.AGE_KEY,
newValue,
.OBJC_ASSOCIATION_ASSIGN)
}
}
}
func associatedUse(){
/**
在Swift中,class依然可以使用关联对象
默认情况,extension不可以增加存储属性
借助关联对象,可以实现类似extension为class增加存储属性的效果
*/
let p = LCPerson182()
print(p.age) // 0
p.age = 10
print(p.age) // 10
}
资源名管理
//七、资源名管理
func sourceNameManager() -> Void {
/**
/// 资源管理方式 这种做法实际上是参考了Android的资源名管理方式
enum R {
enum button: String {
case add = "添加"
case del = "删除"
}
enum image: String {
case logo
}
enum segue: String {
case login_main
}
}
*/
/**
/// 创建一个imageView
/// - Returns: void
private func __createBtn() -> Void {
let btn = UIButton(type: .custom)
//btn.setTitle("添加", for: .normal)
btn.setTitle(R.button.add.rawValue, for: .normal)
btn.frame = CGRect.init(x: 20, y: 20, width: 100, height: 60)
btn.backgroundColor = UIColor.green
self.view.addSubview(btn)
}
/// 创建一个imageView
/// - Returns: void
private func __createImgView() -> Void {
//let img = UIImage(named: "logo")
let img = UIImage(named: R.image.logo.rawValue)
let imageView = UIImageView.init(image: img)
imageView.frame = CGRect.init(x: 20, y: 100,
width: self.view.frame.size.width-40,
height: 100)
self.view.addSubview(imageView)
}
*/
}
行者常至,为者常成!