Swift 代码笔记
2020-04-15 本文已影响0人
帅气的阿斌
import UIKit
print("字符串拼接插值")
func test(){
var a = "1"
var b = "2"
var c = "3"
//字符串拼接
var d = a + b + c;
//插值 \代表转义
var group = "\(a+b)+\(c)"
}
print("类型转换")
var typeturn = Double(10)
print("类型别名")
typealias Bindouble = Double
print("元组")
func test1(){
//元组
var ary = (1,3,"3")
print("元组:\(ary)")
}
print("! ?")
func test2(){
//可选类型 类似泛型
var isdouble:Double? = 13.0
var isfloat:Float?
var isString:String = "1"
print(isString)
}
print("断言")
func test3(){
//断言
var orderId = "123"
assert(orderId.count>0,"断言不成立,中断程序")
}
print("空合并运算 ??")
func test4(){
//空合并运算 (a ?? b) 如果a为nil 则 执行b 否则执行a 因为a可以是nil,所以a必须是可选类型 a和b的值类型必须保持一致
//var aa:String? //aa为nil
var aa:String? = "我是aaa"
var bb = "我是bbb"
var cc = (aa ?? bb)
}
//区间运算符 1...5 范围在[1~5] 1..>5范围在[1~5)
print("区间运算符")
func test5(){
for i in 1...5 {
print(i)
}
for i in 1..<5 {
print(i)
}
}
//test()
//test1()
//test2()
//test3()
//test4()
//test5()
//字符串
func test6(){
var string1 = "12"
var string2 = String();
string2.append("append+")
string2.append((string1))
//判断字符串相等
var string3 = "12"
if string1 == string3 {
print("相同")
}else{
print("不相同")
}
}
//test6()
//字典
func test7(){
var dict = ["key": "23232", "key2": "value2"]
//添加内容
dict.updateValue("value3", forKey: "key3")
print(dict)
for (key, value) in dict {
print(key+"="+value);
}
//声明字典内容类型
var dict2 = [String: Int]()
dict2["key"] = 123
//报错
// dict2["key2"] = "123"
}
//test7()
//控制流
func test8(){
switch 30 {
case 1...20:
print("1~20之间")
case 21...30:
print("21~30之间")
default:
print("默认执行")
}
}
test8()
var btn = UIButton(type: .custom)
btn.frame = CGRect(x: 0, y: 0, width: 10, height: 10)
btn.backgroundColor = UIColor.red
var tbView = UITableView(frame: CGRect.zero, style: .grouped)
let view = UIView()
func test9(){
// str可以为nil,或者有字符串值
var str: String?
print(str)
// str2!表示str2必须有值,否则print(str2!)运行时会报错
var str2: String?
// print(str2!)
// 用于进行!!!非nil!!!, 并不是判断boo值,比如para是false {...}也是依然会被执行,判断的逻辑处理
var para: String? = "haha"
if para != nil {
//do someting
}
// 于以上用if判断效果相同
if let finalPara = para {
//do someting
}
// var string: String?
var string: String? = ""
// if let name = string{
// print("string有值,括号代码被执行,且string会被赋值给name,且name仅在本{}起作用")
// print(name)
// }
// 与if let效果相反,因为有else,为nil时则执行{}代码块,并且nnnn的作用域比if大
guard let nnnn = string else {
print("string为nil时执行")
//必须有return
return
}
// 取nnnn值不会报错
print(nnnn)
// var a = false
// //❌ 直接编译报错
// if a = true {
// print("a is true")
// }
}
test9()
func switchTest10(){
let a = 10
switch a {
case 9:
print("case 9")
fallthrough
case 10://满足该case
print("case 10")
print("case 10")
print("case 10")
print("case 10")
print("case 10")
fallthrough//表示继续执行下一个case,但是这里的fallthrough不能决定下下个case(default)被执行
case 11:
print("case 11")//default并不会执行
default:
print("default")
}
}
switchTest10()
func arrayTest11(){
var ary: [String]? = ["1", "2", "3"]
print(ary)
var dict: [Int: String]?
dict = [1: "nihaoya", 2: "woyehao"]
print(dict!)
var set: Set<String>?
set = ["1", "2", "3"]
print(set!)
var set2: Set<String> = ["1", "2", "3", "4"]
if set == set2 {
print("set == set2")
}else{
print("set != set2")
}
print(set == set2)
//不管t是false还是true print都会被执行 因为这只判断是否为nil
if let t: Bool = (set == set2){
print("t == \(t)")
}
}
arrayTest11()
//函数
func funcTest12(para1: Int, para2: String) -> (a: String, b: Int) {
print("\(para1),\(para2)")
return (para2, para1)
}
var restul12 = funcTest12(para1: 1, para2: "2")
//返回值的输出
print(restul12.a)
print(restul12.b)
//若para 没传入值,则默认为10
func funcTest122(para: Int = 10){
print(para)
}
funcTest122()
funcTest122(para: 11)
//参数名前加 _ 表示调用函数时可忽略参数名,此时再调用方法则不能再显示表名参数
//a: [String], b: [String] 也可写成 [String], [String]
func functest13(_ para1: Int, para2: String) -> (a: [String], b: [String]){
return (["2", "2"],["3", "3"])
}
//var result13 = functest13(para1: 1, para2: "2") //此时再调用方法则不能再显示表名参数,这个在 _ 后调用会报错
var result13 = functest13( 1, para2: "2")
//参数名前加 _ 表示调用函数时可忽略参数名
functest13(1, para2: "2")
//可变参数, 该函数接收由 Int 组成的数组参数 一个函数最多只能有一个可变形式参数。
func varParas(a: Int...) -> Void{
print(a)
}
varParas(a: 1,2,3,4,5)
// inout 修饰参数 输入输出 表示方法对输入参数的修改影响到原始值
var paraValue = 10
func changePara(para: inout Int){
para = 12
}
changePara(para: ¶Value)//由&可知 inout 实际实现的是指针传递(地址传递),所以修改会影响到原始值
print(paraValue)
//外部参数名
func funcparatype2(outa a: Int, outb b: Int){
print("closure")
}
funcparatype2(outa: 10, outb: 100)
func funcparatype(a: Int, b: Int){
print("closure")
}
funcparatype(a: 10, b: 100)
//闭包 closure (amount: Int)参数 第一个->后跟着 () -> Int 为返回值
func makeIncrementor(amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
var incrementfun = makeIncrementor(amount: 10)
incrementfun();
incrementfun();
incrementfun()
incrementfun = makeIncrementor(amount: 10)
incrementfun();
incrementfun();
incrementfun()
/*闭包通用表达式语法
{ (parameters) -> (return type) in
statements
}
*/
//声明函数的另一种方式: 闭包代码块 可替代一般的函数声明 func funcname(...){...}
let fuuunc = {(para1: String, para2: String) -> String in
print("dddddd")
return "dddddd"
}
fuuunc("1", "2")
//关于函数作为返回值
//=>函数作为返回值,那函数类型是什么?
/*y声明一个函数的一般形式
func funcName (para: Int) -> Int {}
*/
//我们可以理解为 func funcName = (para: Int) -> Int {}
//funcName是函数名 右边是函数执行块
//也就是说函数其实就是 = 号右边的部分,{}是函数体部分,那我们就可以简单理解可以把 (para: Int) -> Int 看成是函数体的类型,是用来修饰{}的
//结论:函数类型可以用 (parameters) -> (return type) 表示
//e.g (Int) -> String 表示的是 一个为Int的参数返回值为string的函数
func returnFunc() -> (Int) -> String{
func beReturnedFunc(a: Int) -> String{
return "ha"
}
return beReturnedFunc(a:)
}
//函数类型可以用 (parameters) -> (return type) 表示
//尾随闭包:实际就是函数作为参数传递 someClosure为参数名; () -> Void表示该参数是一个参数为空,无返回值的参数类型
func tailClosure(para: String, someClosure: () -> Void){
print(para)
someClosure()
}
tailClosure(para: "ha") {
print("闭包执行")
}
//全参数尾随闭包示例
func tailClosure2(para1: String, para2: String, someFunc: (_ sPara1: String, _ sPara2: String) -> ( r1: String, r2: String)) -> ( r3: String, r4: String){
print("para1 = " + para1 + " para2 = " + para2)
var someFuncResult = someFunc("闭包参数1", "闭包参数2")
// ❌Cannot convert return expression of type '(r1: String, r2: String)' to return type '(r3: String, r4: String)'
// return someFuncResult
// 修改成以下返回则正确
return (someFuncResult.r1, someFuncResult.r2)
}
//或者闭包函数和函数返回值 名保持一致
func tailClosure3(para1: String, para2: String, someFunc: (_ sPara1: String, _ sPara2: String) -> ( r1: String, r2: String)) -> ( r1: String, r2: String){
print("para1 = " + para1 + " para2 = " + para2)
var someFuncResult = someFunc("闭包参数1", "闭包参数2")
return someFuncResult
}
var resultValue = tailClosure2(para1: "普通参数1", para2: "普通参数2") { (str1, str2) -> (r1: String, r2: String) in
print("闭包执行")
// 注意!!!!这里是闭包的返回值 不是 tailClosure2 函数的返回值!!!!!!!
return ("闭包返回参数1", "闭包返回参数2")
}
print(resultValue)
//关于闭包是否 对常量是值复制还是地址复制呢
//函数接收基本数据类型的数据后 参数为 let类型 不可改变!!!
//var valuetemp = 10
////❌Cannot assign to value: 'para' is a 'let' constant
//let closureGetValue = { (para: Int) -> Int in
// para = para + 1
// return temp
//}
//closureGetValue(valuetemp)
//逃逸闭包 概念:函数作为参数传入到另一个函数中,但是在另一个函数中并没有直接调用,外部变量 funtempfinal 又引用了该函数,在 mainFunc 调用完毕后 又继续使用 funtempfinal 再进行调用,此时就必须使用 @escaping 来修饰 否则编译报错
//简单来说就是函数C 作为参数传入函数A 但是函数A并没有调用函数C,而是使用了外部的变量又引用了函数C,函数A执行完后又通过外部变量调用函数C
//于此对比的是 para 参数,普通类型的值传递则不需要什么逃逸~
var funtempfinal: () -> Void = { () -> Void in
print("初始化 funtempfinal 变量")
}
var outPara: String? = nil
func mainFunc( para: String, func1: @escaping () -> Void ){
print("mainFunc")
outPara = para
funtempfinal = func1
}
mainFunc(para: "para") {
print("func1")
}
//在 mainFunc 调用后,再调用
funtempfinal()
print(outPara)
//最简单的一个代码块
let autoClosure = {
print("666")
}
var b = autoClosure()
//自动闭包
//自己实现一个 assert 断言
//assert(<#T##condition: Bool##Bool#>, <#T##message: String##String#>)
// 参照assert用法 定义两个参数 condition 与 message condition为函数作为参数传入,表达是应是判断句,即表达式要返回bool值
func customAssert( _ condition: () -> Bool, _ message: String ){
if condition() {
print("正确")
}else{
print("错误")
print(message)
}
}
//一般调用
customAssert({ () -> Bool in
return 1 > 2
}, "1<2")
//自动闭包调用 自动闭包的效果=> !不接受任何参数 表达式的值作为结果返回! {1>2} 则表示无参函数,且表达式 1>2 的结果值作为返回值返回
customAssert({1>2}, "1<2")
//到这里基本实现了类似assert的效果 但是还是差点 多了个 {}
//@autoClosure 简单来说 @autoclosure 就是把传入的表达式自动打包成闭包(自己加上{})
func betterCustomAssert( _ condition: @autoclosure () -> Bool, _ message: String ){
if condition() {
print("正确")
}else{
print("错误")
print(message)
}
}
//至此我们实现了和assert一模一样的断言
betterCustomAssert(1>2, "1<2")
//枚举
enum Fruit{
case banana, apple, tomato
}
var fruitName = Fruit.apple
fruitName = .tomato
switch fruitName {
case .banana:
print("香蕉减肥")
case .apple:
print("苹果减肥")
case .tomato:
print("土豆不减肥")
default:
print("啥")
}
var fruitV = Fruit.apple
//枚举的遍历
enum Animals: CaseIterable{
case Monkey
case Cow
case Duck
}
for animal in Animals.allCases{
print(animal)
}
//枚举默认值 定义默认值时 值类型要保持一致
enum DefaultEnum: Int {
case d1 = 1
case d2 = 2
}
//可通过原始值取对应的case
var rawCase = DefaultEnum(rawValue: 2)
//获取case的原始值
var rawCaseValue = rawCase?.rawValue
enum DefaultEnum2: String {
case d1 = "1"
case d2 = "2"
}
//可通过原始值取对应的case
var rawCase2 = DefaultEnum2(rawValue: "2")
//枚举关联值
//类似数据库联合键的概念 比如我想把 来自
//非洲 青色 单个净重1000克的香蕉归为一类 欧洲 黄色 单个净重1000克的香蕉归为一类
//非洲 到货日期10天的香蕉归为一类
enum SuperBanana{
case areaColorWeight(String, String, Double)
case areaDate(String, Double)
}
//非洲 青色 单个净重1000克的香蕉
let 非洲青色单个净重1000克的香蕉 = SuperBanana.areaColorWeight("非洲", "青色", 1000.0)
let 非洲到货日期10天的香蕉 = SuperBanana.areaDate("非洲 ", 10)
switch 非洲青色单个净重1000克的香蕉 {
case SuperBanana.areaColorWeight(let area, let color, let weight):
print("\(area) \(color) \(weight)")
case SuperBanana.areaDate(let area, let date):
print("\(area) \(date)")
default:
print("default")
}
switch 非洲到货日期10天的香蕉 {
case SuperBanana.areaColorWeight(let area, let color, let weight):
print("\(area) \(color) \(weight)")
case SuperBanana.areaDate(let area, let date):
print("\(area) \(date)")
default:
print("default")
}
//递归枚举 实际应用和概念是啥玩意????
//结构体、类及对象
func classStructTest(){
let btn = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
//不同于OC swift可直接设置结构体中的属性
btn.frame.size.height = 200
print(btn.frame)
//值类型是一种当它被指定到常量或者变量,或者被传递给函数时会被拷贝的类型。 引用类型是指针拷贝
//swift中结构体和枚举是值类型 类是引用类型
struct Screen{
var width: Float?
var height: Float?
}
var aScreen = Screen(width: 100, height: 100)
var bScreen = aScreen
bScreen.width = 200
print("aScreen \(aScreen.width) bScreen \(bScreen.width)")
//aScreen Optional(100.0) bScreen Optional(200.0)
}
// === == 比较相等
func compare(){
//!!!!!!类是引用类型
class BinObject{
var name: String?
}
let obj = BinObject()
let objj = obj
let obj2 = BinObject()
//比较引用的是否是同一个对象 即比较引用内存的指针地址
let a = (obj === objj)
let b = (obj === obj2)
let string = "11"
let stringa = string
let stringb = "11"
let stringresult = (string == stringb)
}
compare()
//结构体
struct StructA{
var width: Double
let height: Double
}
var structA = StructA(width: 100, height: 200)
structA.width = 200
//高度为let属性,一旦被赋值则不可改变
//structA.height = 300
let structB = StructA(width: 100, height: 200)
//结构体一旦用let修饰 其内部属性均变为let 不可再修改
//structB.width = 200
//结构体正常情况下无法通过内部函数/方法修改自身的属性
func testStructFunc(){
struct FuncStructChangeValue{
var height = 0
// func changeHeight() {
// //❌Cannot assign to property: 'self' is immutable
//// height = 10
// height = 10
// }
mutating func changeHeight() {
height = 10
}
}
var demo = FuncStructChangeValue()
demo.height = 10
demo.changeHeight()
demo.height
var demo2 = FuncStructChangeValue()
demo2.height
}
testStructFunc()
//lazy 延迟存储 在访问时才会初始化
//使用lazy修饰属性时,属性必须用var修饰
//你必须把延迟存储属性声明为变量(使用 var 关键字),因为它的初始值可能在实例初始化完成之前无法取得。常量属性则必须在初始化完成之前有值,因此不能声明为延迟。
func lazyTest(){
class A{
var name: String
init(name: String) {
self.name = name
}
}
class LazyProperty {
var name: String?
init() {
print("LazyProperty init")
}
}
class LazyClass {
lazy var lazyP: LazyProperty = LazyProperty()
}
let lazyobj = LazyClass()
print(lazyobj.lazyP)
let aa = A(name: "")
}
lazyTest()
//计算属性 简写设置器
func propertyTest(){
//自己实现一个frame 然后通过center属性获取中心值
struct BinFrame{
var x: CGFloat
var y: CGFloat
var width: CGFloat
var height: CGFloat
//这里读代码断句为 声明 类型为CGPoint 的 center 变量,{}代码块
var center: CGPoint {
get {
return CGPoint(x: x + width*0.5, y: y + height*0.5)
//get 会隐式返回表达式值 以下省略return也可
//CGPoint(x: x + width*0.5, y: y + height*0.5)
}
//set显示声明参数
// set (newCenter){
// x = newCenter.x - width*0.5
// y = newCenter.y - height*0.5
// }
//或者省略 则默认参数为newValue
set {
x = newValue.x - width*0.5
y = newValue.y - height*0.5
}
}
//只读属性的简写 默认为get
var center2: CGPoint {
//省略return
//CGPoint(x: x + width*0.5, y: y + height*0.5)
return CGPoint(x: x + width*0.5, y: y + height*0.5)
}
}
//只读属性 不写set只有get即为只读属性
var binframe = BinFrame(x: 100, y: 100, width: 50, height: 50)
//通过get自动计算center值
print(binframe.center)
//通过set自动设置 x,y,width,height
binframe.center = CGPoint(x: 20, y: 20)
print(binframe.center)
binframe.center2
//类对象同样适用 以下为简单样例
class Frame2{
let a = 10
let b = 11
var c: Int {
return a + b
}
}
let frame2 = Frame2()
print(frame2.c)
}
propertyTest()
// 属性观察者
func observer(){
//struct Example
class Example{
var name: String = "1" {
//willSet(newSetValue)或者适用默认
willSet {
print("will set \(newValue)")
}
//didSet(newDidsetValue)或者适用默认
didSet {
print("didSet \(oldValue)")
}
}
}
var example = Example()
example.name = "2"
print(example)
}
observer()
//初始化 初始化是为类、结构体或者枚举准备实例的过程。这个过需要给实例里的每一个存储属性设置一个初始值并且在新实例可以使用之前执行任何其他所必须的配置或初始化。
//简单来说 类、结构体或者枚举在实例化时必须要对属性进行初始化(可选?除外,可为nil) 初始化可以在属性声明时赋值,也可在对应init方法赋值
func funcInitTest () {
struct FuncInit {
//name可选 init 可不初始化
var name: String?
var age: Int
init() {
// name = "1"
age = 2
print("init funcInit")
}
}
//直接调用 默认使用 init初始化
var funcinter = FuncInit()
funcinter.name = "setvalue"
struct FuncInit2 {
var name: String
var age: Int
//FuncInit2() 默认调用 init
init() {
name = "1"
age = 2
print("init funcInit2")
}
//init必须将所有属性进行初始化,否则编译报错
init(name: String, age: Int) {
self.name = name
self.age = age
print("init funcInit name: age:")
}
}
var funcinter2 = FuncInit2()
var funcinter3 = FuncInit2(name: "1", age: 2)
}
funcInitTest()
//属性包装 概念:类似于注解 被属性包装修饰的属性的getter/setter方法由 属性包装 wrappedValue 值提供的
//本质:使被修饰的属性 在被读取和写入时,调用的是属性修饰器的 setter/getter 方法
func testPropertyWrapper() {
//属性包装
@propertyWrapper
struct A {
var name: String
//映射值 固定为 projectedValue ,通过 $+被属性包装的属性名称获取值,被该属性包装的属性即会被赋予一个映射值
//映射值本质:就是为被修饰的属性再添加一个值,并且这个值通过 $+被属性包装的属性名称获取值
var projectedValue = "作为映射值"
//属性包装必须含有 wrappedValue 属性
var wrappedValue: String {
get {
print("get")
return name
}
set {
name = newValue
//通过set同步修改映射值
projectedValue = "映射值==\(newValue)"
print("set")
}
}
init(wrappedValue: String) {
print("调用初始化方法 init(wrappedValue:")
name = wrappedValue
}
init() {
name = "初始化值"
print("调用初始化方法 init")
}
}
//属性包装的属性初始值问题
struct B {
//调用初始化init(wrappedValue:)
@A(wrappedValue: "initValue")
var bName
//调用初始化init(wrappedValue:)
@A(wrappedValue: "initB2Name")
var b2Name
//调用初始化init
@A()
var cName
//当你为属性指定一个初始值时,Swift 默认使用 init(wrappedValue:) 初始化器来设置包装,所以用该类型包装必须要实现 init(wrappedValue:)
@A
var c2Name = "22"
@A var mapValue: String
}
var b = B()
b.bName//调用的是属性包装器的get方法
b.bName = "setValue"//调用的是属性包装器的set方法
b.cName = "cName"
print(b.$cName)
b.mapValue = "1"
print(b.$mapValue)
//属性包装实现原理 (本质:使被修饰的属性 在被读取和写入时,调用的是属性修饰器的 setter/getter 方法)
struct C {
private var _cName = A()
var cName: String {
set {
_cName.wrappedValue = newValue
}
get {
return _cName.wrappedValue
}
}
}
}
testPropertyWrapper()
//类型属性
func classProperty(){
//static var/let 静态变量/常量
struct StructProperty{
static let idcardNum = "11111"
static var name: String {
return "StructProperty"
}
static var age: Int = 10
}
//static var/let 静态变量/常量
class ClassPropertyC {
static let idcardNum = "22222"
static var name: String {
return "class name"
}
//可被子类复写的类型属性
class var age: Int {
return 10
}
}
class A: ClassPropertyC {
override class var age: Int {
return 20
}
}
}
//类型方法 和类型属性类似 static 或者子类可重写方法的 class
func testClassPropertyAndStaticFunc (){
struct StructA{
static func test(){
}
}
class B {
static func test(){
print("static test")
}
class func test2(){
print("B test2")
}
}
B.test()
B.test2()
class C: B {
//可复写B的类型方法
override class func test2() {
print("C test2")
}
}
C.test2()
}
testClassPropertyAndStaticFunc()
//下标 概念:数组通过下标可获取对应的值或者修改值 如何自定义一个类,也能通过下标操作对应的值
//类、结构体和枚举可以定义下标
func indexFunc (){
struct IndexClass{
// class IndexClass{
var value: Int = 0
subscript(index: Int) -> Int {
get{
return value
}
set{
value = newValue
}
}
static var staValue:Int = 0
// //类型下标 类型class下可被子类覆写
// class subscript(index: Int) -> Int {
//静态下标
static subscript(index: Int) -> Int {
get{
return staValue
}
set{
staValue = newValue
}
}
}
var index = IndexClass()
print(index[10000])
index[1000] = 200
print(index[10000])
print(IndexClass[10000])
IndexClass[1000] = 200
print(IndexClass[10000])
}
indexFunc()
//子类属性/方法重写 setter/getter
func testExtend() {
class SuperClass {
var name: String?{
didSet {
}
}
//final修饰,类的方法、属性或下标脚本 无法被重写
final var age: Int?
func test() {
print("test")
}
}
class SonClass: SuperClass {
override var name: String?{
// 'didSet' cannot be provided together with a getter
// get {
// return name
// }
// 'didSet' cannot be provided together with a setter
// set {
// name = newValue
// }
//监视属性变化
didSet {
print("name changed" + self.name!)
}
}
}
let son = SonClass()
son.name = "newname"
son.age = 10
}
testExtend()
//初始化方法
func testInit() {
class TestInitClass {
//类
//let修饰值可在 init 初始化
let name: String
init(name: String) {
self.name = name
}
init() {
name = "defaultvalue"
}
}
let testInitC = TestInitClass()//TestInitClass(name: "newvalue")
print(testInitC.name)
struct TestInitStruct {
let name: String = "name"
let age: Int = 10
}
let stru2 = TestInitStruct()
}
testInit()