目录
基础知识
获取字符串长度
swich case语句
数组的创建
编辑
数组的编辑
编辑
数组的排序
编辑
数组的遍历
编辑
字典的增删改查
编辑
函数
设置可变的函数参数数量
函数的嵌套
常用的内置函数
枚举
类
类的初始化
类的set和get
类的静态方法
类的析构函数
编辑
闭包
计算属性
存储属性的属性观察者
类型属性
访问权限
编辑
值类型和引用类型
如果只需判断字符串的前部分和后部分是否与另一个字符串相同,可以使用hasPrefix()方法和hasSuffix()方法,分别用来判断一个字符串的前面或者后面是否包含某个字符串。
可以使用uppercased()和lowercased()方法进行英文字符串的大小写转换。
var num = 0
let hello = "13028833012"
for temp in hello.characters
{
if temp == "1"
{
num += 1
}
}
print(num)//结果为2
(2,3)>(1,3)//true
("Class1",98)>("Class2",54)//flase
(7,"Sunday")==(7,"Sunday")//true
swift 中的switch匹配到一条case就会完成整个switch语句 ,可通过fallthrough进入到下一个case。
swift提供了数组的添加修改和删除方法
定义函数时,如果不确定参数的数量,可通过在变量类型后面加...定义可变参数。一个函数最多有一个可变参数,且必须是函数表中的最后一个,为避免在调用函数时产生歧义。
func get Average(numbers: Double...) -> Double{}
import UIKit
func chooseNumber(needBigger: Bool,number1: Int,number2: Int)
{
func getSmaller()
{
print((number1 < number2) ? number1 : number2)
}
func getBigger(){
print((number1 > number2) ? number1 : number2)
}
needBigger ? getBigger : getSmaller
}
abs绝对值函数
min最小值函数
max最大值函数
filter函数:通常用于查找在数组元素中满足指定条件的元素
map函数:通常用于将数组中的每个元素通过指定的方法进行转换
reduce函数:可以把数组元素组合计算为一个值,比如将数组中的每个数字进行相加或相乘
enum UserLevel
{
case 总经理
case 主管
case 区域经理,业务员
}
enum Gender: UInt8
{
case Male = 1,Female,Unknow
}
print(Gender.Female.rawValue)
class Car
{
var brand: String
var speed: Int
init()
{
self.brand = ""
self.speed = 0
}
}
类的属性必须初始化
类属性的set和get方法,获取时调用get,设置时调用set
当类当实例引用计数为0时,系统会自动调用析构函数,无法手动调用。
import UIKit
//函数
func test1(a: String, b: String) -> String {
return a + b
}
print(test1(a: "hello,", b: "swift"))
//闭包
let test = { (a: String, b: String) -> String in
return a + b
}
//调用闭包时,不要指定它的外部参数
print(test("hello,", "swift"))
import UIKit
let test = {10}
print(test())
let test2 = {print($0,$1,$2)}
test2(10,20,30)
尾随闭包:
闭包是最后一个参数,按下回车,即可转变为尾随闭包。
import UIKit
func calculate(a: Int,b: Int,fn: (Int,Int) -> Int) -> Int {
return fn(a,b)
}
let value1 = calculate(a: 1, b: 2, fn: { (x,y) in
x + y
})
print(value1)
let value2 = calculate(a: 3, b: 4) { x, y in
x * y
}
print(value2)
let value3 = calculate(a: 10, b: 20, fn: {$0 - $1})
print(value3)
let value4 = calculate(a: 20, b: 5) {$0 / $1}
print(value4)
捕获变量:
import UIKit
func generator() -> () -> Int{
var total = 0, step = 1
func fn() -> Int {
total += step
return total
}
return fn
}
let next = generator()
print(next())//1
print(next())//2
let next2 = generator()
print(next2())//1
print(next2())//2
let next3 = next2
print(next3())//3
print(next3())//4
自动闭包:
自动闭包不接受任何参数,当它被调用的时候,会返回被包装在其中的表达式的值。
自动闭包只有一行代码且需要加标识@autoclosure
import UIKit
func make_autoclosure(_ closure: @autoclosure () -> String){
print("do_autoclosure \(closure())")
}
var array = ["a","b","c","d"]
make_autoclosure(array.remove(at: 0))//a
import UIKit
func myasset(_ closure: @autoclosure () -> Bool,_ str: String?){
if closure(){
if str != nil{
print(str!)
}
}
}
myasset(1<2, "条件为真")
逃逸闭包:
比如loadData方法进行网络请求,当网络响应后调用闭包,可是loadData这个方法早已经执行完毕,这样闭包就脱离了loadData方法的作用域,并还持有相关对象的引用。
逃逸闭包能规避循环引用的风险
import UIKit
typealias ResponseBlock = (_ data: Dictionary?,_ error: Error?) -> Void
func getRequest(url: String,body: Dictionary?,_ handle: @escaping ResponseBlock) {
handle(Dictionary(),nil)
}
class Test {
var url = "http://www.baidu.com"
func testEscaping(){
getRequest(url: url, body: nil) { (data, error) in
print(self.url)//此处必须显示地引用self,否则编译错误
}
}
}
let tt = Test()
tt.testEscaping()
import UIKit
var handlers: [() -> Void] = []
func test(hander: @escaping () -> Void) {
handlers.append(hander)
}
//在该例子中,闭包作为参数并没有在方法结束前调用,而是储存在数组了,闭包调用和结束时机是不可预知的,所以应使用逃逸闭包
import UIKit
struct Rect{
var originX: Double
var originY: Double
var width: Double
var height: Double
//可以使用同级的属性
var centerX: Double{
//从外部读取时会触发get操作
get{
let centerX = originX + width / 2
return centerX
}
//赋予新值设置新属性
set(newCenterX){
originX = newCenterX - width / 2
}
}
var centerY: Double{//必须标明类型
get{
let centerY = originY + height / 2
return centerY
}
set{
originY = newValue - height / 2
}
}
//只读,只能进行读取不能进行修改;只有一个getter可以省略get
var area: Double{
get{
width*height
}
}
}
var square = Rect(originX: 0, originY: 0, width: 10, height: 10)
//触发get代码
let initialSquareCenterX = square.centerX
let initialSquareCenterY = square.centerY
//触发set代码
square.centerX = 15
square.centerY = 15
面向对象的写法
struct Point{
var x = 0.0, y = 0.0
}
struct Size{
var width = 0.0, height = 0.0
}
struct Rect{
var origin = Point()
var size = Size()
var center: Point{
get{
let centerX = origin.x + size.width / 2
let centerY = origin.y + size.height / 2
return Point(x: centerX, y: centerY)
}
set(newCenter){
origin.x = newCenter.x - size.width / 2
origin.y = newCenter.y - size.height / 2
}
}
}
var square = Rect(origin: Point(x: 0, y: 0), size: Size(width: 10, height: 10))
let initialSquareCenter = square.center
square.center = Point(x: 15, y: 15)
import UIKit
//给存储属性设置属性观察者
class Product{
//给初始值或用初始化构造器都不会调用willset和didset
var price = 0{
willSet(newPrice){//自定义变量名,原名newValue
//给属性赋值之前调用
print(newPrice)
}
didSet{
//给属性赋值之后调用
print(oldValue)
}
}
}
let product = Product()
product.price = 8
实际应用
//给存储属性设置属性观察者
class Product{
//给初始值或用初始化构造器都不会调用willset和didset
var price = 5000{
willSet(newPrice){//自定义变量名,原名newValue
//给属性赋值之前调用
print(newPrice)
}
didSet{
//给属性赋值之后调用
print(oldValue)
if price < 4000{
print("通知用户:商品已经降价到您的心理价位了")
}
}
}
}
let product = Product()
product.price = 3999
存储属性用于class,struct
计算属性用于class,struct,enum
属性观察者用于:
1.当前类中新定义的或继承自父类的存储属性
2.继承自父类的计算属性(当前类中新定义的直接使用setter)
import UIKit
struct User{
var name = "张三"
static let standard = User()
}
User.standard
//类型属性:静态属性+类属性
//static虽然可以在类/结构体或枚举中使用,且可以修饰存储属性/计算属性和方法,非常通用,但他修饰的计算属性不能被重写
//class虽然只能在类中使用,且只能修饰类中的计算属性和方法,但修饰的计算属性和方法可以被重写
//总结:若无重写需求,则统一用static,性能更高
类型属性:静态属性+类属性
static虽然可以在类/结构体或枚举中使用,且可以修饰存储属性/计算属性和方法,非常通用,但他修饰的计算属性不能被重写
class虽然只能在类中使用,且只能修饰类中的计算属性和方法,但修饰的计算属性和方法可以被重写
总结:若无重写需求,则统一用static,性能更高
private只能在该文件该作用域内使用
fileprivate只能在同一个swift文件内使用
internal是默认访问权限在同一个modual中使用
public可用于开发第三方功能包时使用
open只能修饰class以及class内的属性和方法,除了public权限外还能在别的modual中实现对该modual的继承和重写
值类型存栈中。
引用类型存堆中,会在栈中存一个他的引用地址。
let修饰的引用类型,仍旧可以修改他下面的属性(因为栈中存的是地址),而struct不可以。
值类型中的内容不能随意改变,必须复制一份才能修改,使用mutating关键字可复制一份。
import UIKit
//内存:栈(stack),堆(heap)
struct StructPerson{
var name: String
var gender: String
mutating func changeName(name: String){
self.name = name
}
}
//值类型-value type-数据直接存在栈中(除class和function/闭包之外都是值类型)
//优点:简单,快,可以深拷贝,真正的不变性,不会内存泄露(后述)
var structPerson1 = StructPerson(name: "张三", gender: "男")
var structPerson2 = structPerson1 //深拷贝
structPerson2.name = "张大花"
structPerson1.name
//let a = 1
//a = 3
//let structPerson3 = StructPerson(name: "李四", gender: "男")
//structPerson3.name = "李大花"
class ClassPerson{
var name: String
var gender: String
init(name: String , gender: String) {
self.name = name
self.gender = gender
}
func changeName(name: String){
self.name = name
}
}
//引用类型-reference type-数据在栈中存储的是它的引用地址(真正存在堆中)
//优点:可以继承
var classPerson1 = ClassPerson(name: "张三", gender: "男")
var classPerson2 = classPerson1 //浅拷贝
classPerson2.name = "张大花"
classPerson1.name
let classPerson3 = ClassPerson(name: "李四", gender: "男")
classPerson3.name = "李大花" //虽然定义为let,但仍旧可以修改里面的属性