可选类型(?)
隐式解析可选类型(!)
结构体
类
协议
扩展
闭包
demo截图.png
import Foundation
//MARK:--------------------Swift中的"?"和"!"--------------------
/*
1. 在swift中可选类型(optionals),用"?"表示,用于处理值缺失的情况,表示"这儿有一个值,且它等于x"或者表示"这儿没有值"
2. 可选类型是一个包含两种情况的枚举值,None和Some,用来表示可能有值或可能没有值
2.1. nil就是Optional.None,当声明一个可选变量或者可选属性的时候,没有提供初始值,它的值默认为nil
2.2. 非nil就是Optional.Some
3. 任何类型都可以明确地声明为可选类型,当声明一个可选类型时,要确保用括号给"?"操作符一个合适的范围。例如:声明可选整数数组,应该写成"(Int[])?",如果写成"Int[]?",就会报错
*/
// 定义一个可选类型:以下两种声明方式是相等的
var Optional_1 : Int?// 在数据类型和"?"之间没有空格
var Optional_2 : Optional<Int>
var intNumber : Int? = 100
// 打印出来以后是一个Optional类型的值
print(intNumber)
// 如果要取到100,必须对可选类型强制解析
print(intNumber!)
// 4. "!":用来强制解析,如果可选类型实例包含一个值,可以用"!"来访问这个值
// 注意:可选类型分为有值和没值,如果可选类型的变量没值时对其强制解包,程序就会崩溃,如下面的程序:
/*
var Number : Int?
print(Number!)
*/
/*
5. 自动解析(隐式解析)
5.1 可以在声明可选变量时,使用"!"来替换"?",这样可选变量在使用时就不需要再加一个"!"来取值了,它会自动解析
5.2 隐式解析可选类型,和可选类型一样,都是有值和没有值(nil)两种结果
5.3 区别是赋值时,隐式解析可选类型不需要再强制解析
5.4 注意:隐式解析可选类型的变量没有值时,程序一样会崩溃
*/
var IntNumberOne : Int! = 10
print(IntNumberOne)
/*
6. 可选绑定
6.1 可选绑定:用来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者临时变量
6.2 可选绑定可以用在if和while语句中来对可选类型的值进行判断,并把它赋给一个常量或者变量
6.3 如果不确定可选类型是否有值,用可选绑定,不需要对可选类型强制解析
*/
var intNumberTwo:Int?
if var intNumberThree = intNumberTwo
{
print("可选类型有值 = ", intNumberThree)
}
else
{
print("可选类型无值")
}
//MARK:----------------------Swift中的结构体---------------------
/*
1. 与C和OC不同的是:
1.1 结构体不需要包含实现文件和接口文件
1.2 结构体允许我们创建一个单一文件,且系统会自动生成该结构体用于面向其他代码的外部接口
2. 结构体总是通过被复制的方式在代码中传递,因此,原本结构体的值是不可修改的
3. 结构体的应用
3.1 在代码中,可以使用结构体定义自定义数据类型
3.2 按照通用的准则,当符合一条或者多条以下条件时,请考虑构建结构体
3.2.1 结构体的主要目的是用来封装少量相关简单数据
3.2.2 有理由预计一个结构体实例在赋值或者传递时,封装的数据将会被拷贝而不是引用
3.2.3 任何结构体中存储的值类型属性,也将会被拷贝,而不是被引用
3.2.4 结构体不需要去继承另一个已存在类型的属性或者行为
4. 例如:
4.1 几何形状的大小,封装一个width属性和height属性,两者均为double类型
4.2 一定范围的路径,封装一个start属性和length属性,两者均为 Int类型
4.3 三维坐标系内的一点,x,y,z属性,三者均为double类型
*/
// 格式:struct + 结构体名字 + {结构体实现}
struct Frame
{
// 存储属性 就是类或结构体里定义的变量(或常量)
var x : Float
var y : Float
var width : Float
var height : Float
// 计算属性 除存储属性外,类、结构体和枚举可以定义计算属性.计算属性不直接存储值,而是提供一个getter和一个可选的setter,来间接获取和设置其他属性或变量的值
// get方法 :在属性类型后面添加{},使用get关键字声明和实现get方法
// set方法 :同上
// set方法不可以单独出现,必须搭配着get方法才可以出现,但是get方法可以单独出现
var centerX : Float {
get{
return x + width / 2
}
}
var centerY : Float {
get{
return y + height / 2
}
}
// 结构体属性 只能通过结构体去调用
static var myStruct = "我是一个结构体属性"
// 结构体中可以声明和实现成员方法即函数
func sayHI()
{
print("你好,我是一个方法")
}
// 结构体的类方法:方法前用static修饰,只能由结构体调用
static func sayHello()
{
print("hello")
// 结构体类方法中只能调用结构体属性
print(self.myStruct)
}
// 结构体自带有初始化方法,但是也可以重写
init(x newX : Float, y newY : Float, width newWidth : Float, height newHeight : Float)
{
x = newX
y = newY
width = newWidth
height = newHeight
}
}
// 调用结构体属性(因为是结构体属性,所以只能由结构体调用,不能由对象调用)
print(Frame.myStruct)
// 调用结构体的类方法
Frame.sayHello()
// 结构体有自带的构造体方法和初始化方法
// 以下这两种创建对象的方式没区别
var frame : Frame = Frame(x: 10, y: 10, width: 100, height: 100)
var frame1 : Frame = Frame.init(x: 10, y: 10, width: 100, height: 100)
print(frame.centerX)
// 调用Frame结构体的成员方法
frame1.sayHI()
//MARK:-----------------------Swift中的类-----------------------
// 类是人们构建代码所用的一种通用且灵活的构造体。我们可以使用与结构体完全相同的语法规则来为类定义属性(常量、变量)和添加方法
/*
1. swift中,类和结构体有很多共同点
1.1 定义属性,用于存储值
1.2 定义方法,用于提供功能
1.3 定义构造器,用于提供初始化值
1.4 遵循协议,用来对某个类提供标准功能
1.5 通过扩展,用来增加默认实现的功能
2. 与结构体相比,又有其他附加功能
2.1 继承,允许一类继承另一个类的特征
2.2 类型转换允许在运行时检查和解释一个类实例的类型
2.3 引用计数:允许对一个类多次引用
*/
// 值类型:该类型的每个实例持有数据的副本,并且该副本对于每个实例来说是独一无二的一份,比如结构体(struct)、枚举(enum)、元组(tuple)都是值类型
/*
值类型的使用场景:
当使用"=="运算符比较数据的时候
想单独复制一份实例数据的时候
在多线程环境下操作数据的时候
*/
/*
// 创建一个StructObject结构体变量
struct StructObject
{
var data : Int = -1
}
var a = StructObject()
// b是a的拷贝
var b = a
// 更改a的数据,b的不受影响
a.data = 42
print("\(a.data), \(b.data)")
*/
// 引用类型:该类型的实例共享数据唯一的一份副本(在native层面说的话,就是该类型的每个实例都指向内存中的同一个地址),比如类(class)就是引用类型
/*
// 创建一个ClassObject类
class ClassObject
{
var data : Int = -1
}
var a = ClassObject()
// 将a变量的值赋值给b,其实是一个引用的过程
var b = a
// a的数据改变了,但是b也发生了改变
a.data = 42
print("\(a.data), \(b.data)")
*/
/*
使用值类型的情形:
使用 == 运算符比较实例数据的时候
单独复制一份实例数据的时候
在多线程环境下操作数据的时候
使用引用类型(比如class)的情形:
使用 == 运算符判断两个对象是否引用同一个对象实例的时候
当上下文需要创建一个共享的、可变的对象时
*/
// 类的定义格式:class + 类名 + {类的实现}
class Person
{
// 当给一个类写属性的时候,这个属性如果没有初值那就需要是可选类型
// 存储属性
var name : String?
var gender : String?
var age : Int?
// 计算属性
var width : Float {
get{
return 100
}
set{
// set方法中的newValue表示新的值
self.width = newValue
}
}
// 此处static修饰的是类属性
static var hooby : String? = "大播"
// 此处static修饰的是类方法,这时类方法可以调用static修饰的类属性
static func sayMy()
{
print(hooby!)
}
// 没用static修饰的类方法不能调用static修饰的属性
func sayHI()
{
print("你好啊\(self.width)")
name = "污唐"
}
// 声明类方法时,static和class都可以修饰类方法,区别在于class修饰的类方法可以被子类重写。class修饰的类方法可以调用static修饰的属性,但是class自己不能修饰属性
class func saySaWaDiKa()
{
print(hooby!)
}
// 类的构造方法 系统没有自带,需要自己写了才能调用
init(name newName : String, gender newGender : String, age newAge : Int)
{
name = newName
gender = newGender
age = newAge
}
}
// 创建实例对象的两种方式(这两种方式没区别):
var person : Person = Person.init(name: "王梁", gender: "女", age: 8)
var person1 : Person = Person(name: "鸭王", gender: "女", age: 3)
// 调用实例对象的属性
print(person.age!)
// 实例person1调用实例方法sayHI()
person1.sayHI()
// 类Person调用static修饰的类方法sayMy()
Person.sayMy()
// 类Person调用class修饰的类方法saySaWaDiKa()
Person.saySaWaDiKa()
class student : Person
{
var number : NSString?
// 重写父类的方法 :需要添加override修饰
override func sayHI()
{
print("重写方法")
}
// 重写父类的init构造方法
override init(name newName : String, gender newGender : String, age newAge : Int)
{
super.init(name: newName, gender: newGender, age: newAge)
name = newName
gender = newGender
age = newAge
}
// 在重新创建一个init方法的时候 还是需要super.init
init(number newNumber : NSString)
{
super.init(name: "张三", gender: "男", age: 1)
number = newNumber
}
}
var stu1 : student = student.init(name: "小明", gender: "男", age: 9)
stu1 = student.init(number: "007")
print(stu1.name!,stu1.number!)
stu1.sayHI()
//MARK:----------------------Swift中的协议-----------------------
/*
协议定义了一个蓝图,规定了用来实现某一特定工作或者功能所必需的方法和属性
类、结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能
任意能够满足协议要求的类型被称为遵循(conform)这个协议
*/
// 声明协议
// protocol声明的协议,表示Swift的协议,所有的方法都必须实现
protocol myDelegate
{
// 协议方法
func test()
// 使用mutating修饰的函数,可以在结构体里面修改结构体的属性
// 在协议里面使用mutating修饰的函数,在遵守协议的时候,类里面不能使用mutating修饰。但是在结构体里面,如果要修改属性的话必须用mutating修饰方法
mutating func change()
}
// @objc修饰的协议表示这个协议是OC的协议,可以声明可选实现的函数,在函数名前面用optional修饰,这个函数就是可选实现的了
@objc protocol newDelegate
{
optional func newTest()
func newChange()
}
class Teacher : Person, myDelegate, newDelegate {
// 必须实现的方法
func test()
{
name = "111"
print("aaa")
}
// 必须实现的方法
@objc func newChange()
{
}
// 必须实现的方法
// 协议里面使用mutating修饰的函数,在类里面就是一个普通的函数
func change()
{
name = "100"
}
// 可选实现的方法
@objc func newTest()
{
}
}
let teacher :Teacher = Teacher(name: "a", gender: "b", age: 111)
teacher.test()
// @objc修饰的协议 结构体不能遵循
struct myStruct : myDelegate
{
var name : String
// 一般不能直接修改结构体里面的属性
func test()
{
}
// mutating修饰的方法里可以修改结构体的属性
mutating func change()
{
name = "111"
}
}
//MARK:----------------------Swift中的扩展-----------------------
// extension + 类名(结构体名字) 可以对一个类或结构体扩展方法
// extension不能扩展属性
// extension也可以给类或结构体扩展协议方法 这个在开发的时候最有用
extension Person : myDelegate // 给Person类扩展协议
{
// 实现协议里的方法
func test()
{
}
// 实现协议里的方法
func change()
{
}
// 给Person类扩展方法
func eat()
{
}
}
extension Frame : myDelegate // 给Frame结构体扩展协议
{
// 实现协议里的方法
func test()
{
}
// 实现协议里的方法
func change()
{
}
// 给Frame结构体扩展新的方法
func play()
{
}
}
//MARK:----------------------Swift中的闭包-----------------------
/*
* 闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift中的闭包与C和Objective-C中的代码块(block)以及其他一些编程语言中的匿名函数比较相似。
* 闭包可以捕获和存储其所在上下文中任意常量和变量的引用。这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。Swift会为您管理在捕获过程中涉及到的所有内存操作。
* 语法格式:
{
(参数) -> 返回值类型 in
执行语句
}
* 注意:闭包的函数体部分由关键字in引入。该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数即将开始。
*/
// 使用闭包求两个Int型数的最大值
// 声明一个闭包
var maxValue : ((Int, Int) -> Int)
// 实现闭包的第一种方式
maxValue = {
(a : Int, b : Int) -> Int in
return a > b ? a :b
}
/*
其中:
* maxValue的类型是(Int, Int) -> Int
* maxValue的值就是一个闭包:
{
(a : Int, b : Int) -> Int in
return a > b ? a :b
}
*/
// 第二种方式实现闭包 省略参数类型和返回值
maxValue = {
a, b in
return a > b ? a : b
}
// 第三种方式实现闭包 省略参数类型,省略返回值,省略return关键字
maxValue = {
a, b in
a > b ? a : b
}
// 第四种方式 都省略了 使用$表示取第几个参数
maxValue = {
$0 > $1 ? $0 : $1
}
// 第五种 苹果推荐的格式
maxValue = {
(a, b) -> Int in
return a > b ? a : b
}
print(maxValue(3,5))
网友评论