//
// ViewController.swift
// swift_01
//
// Created by weiphone on 16/8/26.
// Copyright © 2016年 weiphone. All rights reserved.
//
import UIKit
class ViewController: UITabBarController {
enum DayssofaWeek { // 星期
case Sunday
case Monday
case TUESDAY
case WEDNESDAY
case Thursday
case Friday
case Saturday
}
enum Student { // 学生
case Name(String)
case Mark(Int, Int, Int)
func studentSSS(a:Int, b:Int) -> Int {
return a+b
}
}
struct MarkStruct { //结构体
var English: Int
var Chines: Int
var Math: Int
func markStrDid(English:Int, Math:Int) -> Int {
return English+Math
}
// (1) mutating 可以从方法内部改变它的属性;并且它做的任何改变在方法结束时还会保留在原始结构中
mutating func subMarks(english:Int, math:Int) -> Int { //
self.English += english //在可变方法中给self赋值 : 可变方法能够赋给隐含属性 self 一个全新的实例。
Math += math // 改变它的属性,并且它做的任何改变在方法结束时还会保留在原始结构中
print("英语 : ", self.English, self.Math)
return self.English-self.Math
}
// (2) 方法的func关键字之前加上关键字static。类可能会用关键字class来允许子类重写父类的实现方法
static func minMarks(english:Int, math:Int) -> Int {
if english < math {
return english
} else {
return math
}
}
// (3)下标脚本 : subscript
subscript(index:Int) -> Int {
return English / index
}
// (4)下标脚本的重载
subscript(row:Int, columns:Int) -> Int {
get {
return (row * columns) + columns
}
set {
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = UIColor.grayColor()
// let nav1 = UINavigationController.init(rootViewController: FirstViewController)
// let nav2 = UINavigationController.init(rootViewController: FirstViewController)
//
// self.viewControllers:[nav1, nav2]
//
// (1)swift引入
// import语句引入OC框架(或C库)到swift程序中,
// swift应用中可以简单额的混入C、C++语言代码,
// (2)swift标记 : swift程序由多种标记组成, 标记可以是单词、标识符、常量、字符串或符号,
print("test!") // 标记是:单词、符号
// (3)注释
// 与C语言注释极其相似, 不同之处是多行注释可以嵌套在其他的多行注释的内部
// 单行注释: // 多行注释: /* */
/*
/* 嵌套注释 */
*/
// (4)分号 : 不要求每行语句的结尾处使用分号(;), 但是在同一行书写多条语句时要用分号隔开
print("分号;;;;")
let _fenhao:NSString = "分号"; print(_fenhao)
// (5)标识符
// 标识符就是给常量、变量、方法、函数、枚举、结构体、类、协议、等指定的名字
// 命名规则: 可由下划线、数字、字母组成, 不可以数字开头, 区分大小写; 若非要以关键字作为标识符需要在关键字前后添加重音符号(')
// (6)关键字
/* 关键字类似于标识符的保留字符序列,除非用重音符号(')将其括起来, 不然不可作为标识符。 关键字是对编译器具有特殊意义的预定义保留标识符。
{
与声明有关的关键字 : calss func let public typealias deinit import operator static var enum init private struct
extension internal protocol subscript
与语句有关的关键字 : if else for in break continue return do while switch case where default fallthrough
表达式和类型关键字 : is true fale nil as self super dynamic _COLUMN_ _LINE_ _FILE_ _FUNCTION_
在特定上下文中使用的关键字 :
associativity convenience dynamic didSet
final get infix inout
lazy left mutating none
nonmutating optional override postfix
precedence prefix Protocol required
right set Type unowned
weak willSet
}
*/
// (7)swift空格 : 在swift中,运算符不能直接跟在变量或常量的后面
// 错误例 : let aaa= "12344" let aaa = 1 + 2(1 + 语句到此结束, 2是下一个语句)
let aaa = 1 + 2; // 规范编码推荐使用
let bbb = 2+3 // 也 ok
print(aaa,bbb)
// (8)swift字面量 : 指特定的数字、字符串或布尔值这样,能够直接了当的指出自己的类型并为变量进行赋值
42 // 整形字面量
3.14159 // 浮点型字面量
"hellow swift!" //字符串字面量
true // 布尔值字面量
//
//
// (1)常量声明 (使用关键字let声明)
// let constantName =
let constInt = 42
let constFloat = 2.11
let constString = "string"
print(constInt, constFloat, constString)
// (2)类型标注 (添加类型标注,需要在常量或者变量名后面加上一个冒号和空格,然后加上类型名称)
// var constantName: =
let aaInt:Int = 2
let aaFloat:Float = 3.1415926
print(aaInt, "\n", aaFloat)
// (3)常量命名 (由字母,数字和下划线组成, 以字母或下划线开始, 也可以使用简单的 Unicode 字符)
let _const = "hello swift!"
let 你好 = "你好世界"
print(_const, "\n", 你好)
print("\(_const) ...... \(你好)")
// (4)常量输出
// 变量和常量可以使用 print(swift 2 将 print 替换了 println) 函数来输出。
// 字符串中可以使用括号与反斜线来插入常量
let printName = "菜鸟教程"
let printName2 = "http://www.runoob.com"
print("\(printName)的官网地址为:\(printName2)")
//
//
// 变量是一种使用方便的占位符,用于引用计算机内存地址。
// Swift 每个变量都指定了特定的类型,该类型决定了变量占用内存的大小,不同的数据类型也决定可存储值的范围。
// (1)变量声明
// 变量声明的意思是告诉编译器在内存中的哪个位置为变量创建多大的存储空间。
// 使用 var 关键字声明
// var variableName =
var varA = 42
var varB:Float
varB = 3.1415926
varA += 1
print(varA, varB)
// (2)变量命名
// 由字母、数字、下划线组成, 以字母或下划线开始,也可以使用简单的 Unicode 字符
var _varA = "hellow swift!"
_varA = "ni hao!"
print(_varA)
// (3)变量输出
// 变量和常量可以使用 print(swift 2 将 print 替换了 println) 函数来输出。
// 字符串中可以使用括号与反斜线来插入常量
var _varB:NSString = "菜鸟教程"
_varB = "菜鸟教程 "
var _varC:NSString = "http://www.runoob.com"
_varC = " http://www.runoob.com "
print("\(_varB)的官网是:\(_varC)")
//
//
// 使用数据类型存储不同的信息
// (1) 内置数据类型
// 常用数据类型 : Int UInt 浮点数 布尔值 字符串 字符 可选类型
/**
Int : 长度与当前平台的原生字长相同, 在32(64)位平台上,Int和Int32(Int64)长度相同,
在32位平台上,Int可以存储的整数范围 -2,147,438,648~2,147,483,647
UInt : 无符号整形,
浮点数 : {
double : 64位浮点数, 最少15位
float : 32位浮点数, 最少6位
}
布尔值 : true , false
字符串 : 字符串是字符的序列集合 "hellow swift!"
字符 : 指单个字母, “C”
可选类型 : 使用可选类型(optionals)来处理值可能缺失的情况,可选类型表示有值或没值
*/
// (2) 数值范围
/**
类型 大小(字节) 区间值
Int8 1字节 -127 ~ 127
UInt8 1字节 0 ~ 255
Int32 4字节 -2^31 ~ 2^31
UInt32 4字节 0 ~ 2^32
Int64 8字节 -9223372036854775808 ~ 9223372036854775807
UInt64 8字节 0 ~ 18446744073709551615
Float 4字节 1.2E-38 ~ 3.4E+38 (~6 digits)
Double 8字节 2.3E-308 ~ 1.7E+308 (~15 digits)
*/
// (3) 类型别名 : 类型别名对当前的类型定义了另一个名字,类型别名通过使用 typealias 关键字来定义
// 语法格式 typealias newsname = type
typealias zhengxing = Int
let cccInt:zhengxing = 3
print(cccInt)
// (4) 类型安全 : 会在编译代码时进行类型检查(type checks), 把不匹配的类型标记为错误, 可以在开发时尽早发现修复错误
var varCC = 42
// varCC = "hellow swift!" //报错 : cannot assign value of type 'String' to type 'Int'
varCC = 43
print(varCC)
// (5) 类型推断 : 如果没有显式的指定类型,swift会使用推断类型(type inference)来选择适合的类型
let ddInt = 42 // ddInt 会被推断为 Int 类型
let pi = 3.14159 // pi 会被推断为double类型, 浮点数的类型会推断为double, 不是float
let pipi = 3 + 0.14159; // 表达式中同时出现整形和浮点数, 会被推断为double类型
print(ddInt,pi,pipi)
//
//
// 所谓字面量, 就是指特定的数字、字符串或者布尔值这样,能够直接的指出自己的类型并为变量进行赋值的值
// (1) 整型字面量 : 可以是十进制、八进制、二进制或十六进制常量, 二进制前缀0b, 八进制前缀0o, 十六进制前缀0x
let decimalInteger = 17 //17 十进制
let binaryInteger = 0b10001 //17 二进制
let octalInteger = 0o021 //17 八进制
let hexadecimalInteger = 0x11 //17 十六进制
print(decimalInteger,binaryInteger,octalInteger,hexadecimalInteger)
// (2) 浮点型字面量 : 有整数部分,小数点,小数部分及指数部分
// 浮点型字面量的默认推到类型为Double, 表示64位浮点数
// 十进制指数 : 1.25e2 表示 1.25*10^2 , 1.25e-2 表示 1.25*10^-2 (e 或 E)10^
// 十六进制 : 0xFp2 表示 15*2^2 , (p 或 P) 2^
let decimalDouble = 12.1875 //十进制浮点型字面量
let expontDouble = 1.21875e1 //十进制浮点型字面量
let hexadecimalDouble = 0xC.3p0 //十六进制浮点型字面量
print(decimalDouble,expontDouble,hexadecimalDouble)
// (3)字符串型字面量 : 由被包在双引号中的一串字符串组成 "charaters"
// 字符型字面量中不能包含未转义的双引号(“)、未转义的反斜线(\)、回车符或换行符
/**
转移字符 含义
\0 空字符
\\ 反斜线 \
\b 退格(BS) ,将当前位置移到前一列
\f 换页(FF),将当前位置移到下页开头
\n 换行符
\r 回车符
\t 水平制表符
\v 垂直制表符
\' 单引号
\" 双引号
\000 1到3位八进制数所代表的任意字符
\xhh... 1到2位十六进制所代表的任意字符
*/
let stringL = "Hello\tWorld\n\n菜鸟教程官网:\'http://www.runoob.com\'"
print(stringL)
/** 输出
Hello World
菜鸟教程官网:'http://www.runoob.com'
*/
// (4)布尔型字面量 : 默认类型是Bool
// 布尔值字面量有三个值, 是swift的保留关键字: true:表示真, false:表示假, nil:表示没有值
//
//
// swift的可选(optional)类型, 用于处理值缺失的情况, swift语言定义后缀问号 ? 作为命名类型optional的简写,例如以下两种声明相等
/**
var optionalInteger: Int?
var optionalInteger: Optional
*/
// 声明一个可选类型时,要确保用括号给?操作符一个适合的范围, 例如, 声明可选整数数组:(Int[])?, 不是Int[]?
// 声明一个可选变量或者可选属性的时候没有提供初始值,它的值默认为nil
// 如果一个可选类型的实例包含一个值,可以用后缀操作符!来访问这个值,
// 使用操作符!去获取值为nil的可选变量会有运行时错误, 可以用可选链接和可选绑定选择性执行可选表达式上的操作。如果值为nil,任何操作都不会执行,也不会有运行报错。
/**
optionalInteger = 42
optionalInteger! //42
var optionalInteger: Int?
optionalInteger = 42
print(optionalInteger!)
*/
let ccString:String? = nil
if ccString != nil {
print(ccString)
} else {
print("字符串为 nil")
}
// 可选类型类似于OC中的指针的nil值, 但是nil只针对类(class)有用, 而可选类型对所有类型都可用,且更安全。
// (1)强制解析 : 当你确定可选类型确实包含值之后,你可以在可选的名字后面加一个感叹号(!)来获取值。这个感叹号表示"我知道这个可选有值,请使用它。"这被称为可选值的强制解析(forced unwrapping)
var cccStr:String?
cccStr = "hellow swift!"
if cccStr != nil {
print(cccStr!,"\n",cccStr) // 强制解析
} else {
print("字符串为 nil")
}
/**输出
hellow swift! // 强制解析结果
Optional("hellow swift!")
注意:
使用!来获取一个不存在的可选值会导致运行时错误。使用!来强制解析值之前,一定要确定可选包含一个非nil的值。
*/
// (2)自动解析 : 你可以在声明可选变量时使用感叹号(!)替换问号(?)。这样可选变量在使用时就不需要再加一个感叹号(!)来获取值,它会自动解析
var ccccString:String!
ccccString = "自动解析。。。";
if ccccString != nil {
print(ccccString)
} else {
print("字符串为 nil")
}
/**输出
自动解析。。。
*/
// (3)可选绑定 : 使用可选绑定(optional binding)来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在if和while语句中来对可选类型的值进行判断并把值赋给一个常量或者变量。
/**
if let constantName = someOptional {
statements
}
*/
var cccccString:String?
cccccString = "kexuanbangding...."
if let CCCCString = cccccString {
print(CCCCString)
} else {
print("字符串没有值");
}
//
//
// 运算符是一个符号, 用于告诉编译器执行一个数学或逻辑运算。
/**
算数运算符 : + - * / % ++ --
比较运算符号 : == != > < >= <= (结果为true, false)
逻辑运算符 : && || ! (结果为true, false)
位运算符 : 位运算符用来对二进制位进行操作, ~ & | ^ << >>
&(按位与,都为1时才为1,其他为0) |(按位或,有一个为1就为1) ^(按位异或,相同为0,不同为1)
~(按位取反) <<(按位左移,将操作数的所有位向左移指定的位数, 空位用0补充) >>(按位右移,)
赋值运算符 : = += -= *= /= %= <<= >>= &= ^= |=
区间运算符 : 闭区间运算符(a...b) 半开区间运算符(a...
其他运算符 : swift 提供了其他类型的的运算符,如一元、二元和三元运算符.
*/
// 区间运算符
print("闭区间运算符:")
for index in 1...5 {
print("\(index) * 2 = \(index * 2)")
}
print("半开区间运算符:")
for index in 1..<5 {
print("\(index) * 3 = \(index * 3)")
}
// 运算符优先级
/**
指针最优,单目运算优于双目运算。如正负号。
先乘除(模),后加减。
先算术运算,后移位运算,最后位运算。请特别注意:1 << 3 + 2 & 7 等价于 (1 << (3 + 2))&7
逻辑运算最后计算
*/
//
//
/** 条件语句
if 语句
if...else 语句
if...else if...else 语句
内嵌 if 语句
switch 语句
? : 运算符
*/
//
/** 循环类型
for-in
for 循环
while 循环
repeat...while 循环 : 类似 while 语句区别在于判断循环条件之前,先执行一次循环的代码块
*/
/** 循环控制语句
continue 语句
break 语句
fallthrough 语句 : 如果在一个case执行完后,继续执行下面的case,需要使用fallthrough(贯穿)关键字
*/
//
//
// swift 字符串是一系列字符的集合。例如 "Hello, World!" 这样的有序的字符类型的值的集合,它的数据类型为 String
// (1)创建字符串
// 是有字符串字面量
let stringA = "hellow CJstring"
print(stringA)
// String 实例化
let stringB = String("hellow shilihua...")
print(stringB)
// (2)空字符串
// 可以使用空的字符串字面量赋值给变量或初始化一个String类的实例来初始值一个空的字符串。 可以使用字符串属性 isEmpty 来判断字符串是否为空:
let stringAA = "" // 是有字符串字面量创建空字符串
if stringAA.isEmpty {
print("stringAA is empty....")
} else {
print("stringAA is not empty...")
}
let stringBB = String() // 实例化String 类来创建空字符串
if stringBB.isEmpty {
print("stringBB is empty....")
} else {
print("stringBB is not empty...")
}
// (3)字符串常量
// 你可以将一个字符串赋值给一个变量或常量,变量是可修改的,常量是不可修改的。
var stringAAA = "stringAAA is mutable..." // stringAAA 可被修改
stringAAA += "http://www.runoob.com"
print(stringAAA)
let stringBBB = String("stringBBB is can not mutable...") //
// stringBBB += "http://www.runoob.com" // 报错 :left side of mutating operator isn't mutable:'stringBBB' is a 'let' constant
print(stringBBB)
// (4)字符串中插入值
// 字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。 您插入的字符串字面量的每一项都在以反斜线为前缀的圆括号中
let varAaAA = 20
let constaAAA = 100
let varAaAAA:Float = 20.0
let stringAaAA = "\(varAaAA) 乘以 \(constaAAA) 等于 \(varAaAAA * 100)"
print(stringAaAA)
// (5)字符串连接
// 字符串可以通过 + 号来连接
let lianjieA = "连接A..."
let lianjieB = "连接B..."
let lianjieC = lianjieA + lianjieB;
print(lianjieC)
// (6)字符串长度
// String.characters.count
let changduA = "12345678"
print("字符串长度为 \(changduA.characters.count)")
// (7)字符串比较
// 你可以使用 == 来比较两个字符串是否相等
if lianjieA == lianjieB {
} else {
}
// (8)Unicode 字符串
// Unicode 是一个国际标准,用于文本的编码,Swift 的 String 类型是基于 Unicode建立的。你可以循环迭代出字符串中 UTF-8 与 UTF-16 的编码
let unicodeA = "你好吗!"
print("UTF-8 编码:")
for code in unicodeA.utf8 {
print("\(code)","\n")
}
print("UTF-16 编码:")
for code in unicodeA.utf16 {
print("\(code)","\n")
}
// (9)字符串函数及运算符
/**
isEmpty : 判断字符串是否为空,返回布尔值
hasPrefix(prefix: String) : 检查字符串是否拥有特定前缀
hasSuffix(suffix: String) : 检查字符串是否拥有特定后缀。
Int(String) : 转换字符串数字为整型
String.characters.count : 计算字符串的长度
utf8 : 您可以通过遍历 String 的 utf8 属性来访问它的 UTF-8 编码
utf16 : 您可以通过遍历 String 的 utf16 属性来访问它的 UTF-16 编码
unicodeScalars : 您可以通过遍历String值的unicodeScalars属性来访问它的 Unicode 标量编码
+ : 连接两个字符串,并返回一个新的字符串
+= : 连接操作符两边的字符串并将新字符串赋值给左边的操作符变量
== : 判断两个字符串是否相等
< : 比较两个字符串,对两个字符串的字母逐一比较
!= : 比较两个字符串是否不相等
*/
if CFStringHasPrefix(unicodeA, "你") {
print("CFStringHasPrefix.....YES")
} else {
print("CFStringHasPrefix.....NO")
}
if CFStringHasSuffix(unicodeA, "!") {
print("CFStringHasSuffix.....YES")
} else {
print("CFStringHasSuffix.....NO")
}
let zhuanhuanInt:Int! = Int(changduA)
print(zhuanhuanInt)
print("标量编码:")
for code in unicodeA.unicodeScalars {
print("\(code)","\n")
}
//
// Swift 的字符是一个单一的字符字符串字面量,数据类型为 Character
let charA:Character = "A"
print(charA)
// (1)空字符变量 : Swift 中不能创建空的 Character(字符) 类型变量或常量
// let charAA:Character = "" // "" 被推断为String类型
// (2)遍历字符串中的字符
for char in "hellow swift".characters {
print(char)
}
// (3)字符串连接字符
var charAA:String = "连接。。。"
charAA.append(charA)
print(charAA)
//
// Swift 数组使用有序列表存储同一类型的多个值
// (1)创建数组
// var someArray = [SomeType]()
var arrayA = [String]()
var arrayB = [String](count: 3,repeatedValue: "arrayB... ")
var arrayC = [10, 20, 30]
// (2)访问数组 : 可以根据数组的索引来访问数组的元素 var someVar = someArray[index]
var indexB = arrayB[0]
var indexC = arrayC[1]
indexB = "indexBBBB....."
indexC += 40
// (3)修改数组 : 可以使用 append() 方法或者赋值运算符 += 在数组末尾添加元素
arrayA.append("arrayA... ")
arrayA += [indexB]
arrayA += ["\(indexC)"]
arrayB[0] = "arrayBBBBB....."
// (3)遍历数组 : 使用for-in循环来遍历所有数组中的数据项
// 同时需要每个数据项的值和索引值,可以使用 String 的 enumerate() 方法来进行数组遍历
for item in arrayB {
print(item)
}
for (index, item) in arrayB.enumerate() {
print(index, item, "\n")
}
// (4)合并数组 : 使用加法操作符(+)来合并两种已存在的相同类型数组
var arrayD = [String]()
arrayD = arrayA + arrayB
print("输出 arrayD : ", arrayD)
// (5)count属性
print("arrayD 的元素个数是 :\(arrayD.count)")
// (6)isEmpty属性
print("arrayD 是否为空 :\(arrayD.isEmpty)")
//
// 字典 : 用来存储无序的相同类型数据的集合,
// (1)创建字典 :
/**
var someDict = [KeyType: ValueType]() 创建一个特定类型的空字典
*/
var dicA = [String: String]()
var dicB = [Int: String]()
dicA = ["a":"1", "b":"2", "c":"3"]
dicB = [0:"a1", 1:"b2", 2:"c3"]
print(dicA, dicB)
let dicC:[Int:String] = [5:"five...", 6:"six...", 0:"a1"]
print(dicC)
// (2)访问字典 : var someVar = someDict[key]
let keyA:String! = dicA["a"]
print(keyA)
// (3)修改字典 : 使用 updateValue(forKey:) 增加或更新字典的内容。如果 key 不存在,则添加值,如果存在则修改 key 对应的值
dicA.updateValue("d", forKey: "4")
dicA["a"] = "11111"
print(dicA)
// (4)移除Key-Value对 : 可以使用 removeValueForKey() 方法来移除字典 key-value 对。如果 key 存在该方法返回移除的值,如果不存在返回 nil
// 可以通过指定键的值为 nil 来移除 key-value(键-值)对
dicB.removeValueForKey(1)
dicB[0] = nil
print(dicB)
// (5)遍历字典 :
// for (key, value) in dicB { // 两种都可以
for (key, value) in dicB.enumerate() {
print("字典:key : \(key), value: \(value)")
}
// (6)字典转换为数组 : 可以提取字典的键值(key-value)对,并转换为独立的数组
let dicKeyA = [String](dicA.keys)
let dicValueA = [String](dicA.values)
print("dicA的键key : \(dicKeyA)")
print("dicA的值Value : \(dicValueA)")
// (7)属性 : count , isEmpty
print("字典dicB的元素个数: \(dicB.count)......")
print("字典dicB是否为空 : \(dicB.isEmpty).....")
//
//
// Swift 函数用来完成特定任务的独立的代码块, 使用一个统一的语法来表示简单的C语言风格的函数到复杂的Objective-C语言风格的方法
/**
函数声明: 告诉编译器函数的名字,返回类型及参数。
函数定义: 提供了函数的实体。
*/
// Swift 函数包含了 参数类型 及 返回值类型
// (1)函数定义 (2)函数调用
/** 定义函数使用关键字 func 语法
func funcname(形参) -> returntype
{
Statement1
Statement2
……
Statement N
return parameters
}
*/
func resetNickname(userName:String) -> String { // 定义函数
var name:String! = userName
name.appendContentsOf("...........")
return name
}
print(resetNickname("phoebe_zhang")) // 调用
// (3)函数参数 : 函数可以接受一个或者多个参数,我们也可以使用元组(tuple)向函数传递一个或多个参数
func refreshDidView(model1:Int, model2:Int) -> Int {
return model1 * model2
}
print(refreshDidView(3, model2: 5))
// (4)不带参数函数
/** 语法
func funcname() -> datatype {
return datatype
}
*/
func refreshNoti() {
}
refreshNoti()
// (5)元组作为函数返回值 :
// 元组与数组类似,不同的是,元组中的元素可以是任意类型,使用的是圆括号, 你可以用元组(tuple)类型让多个值作为一个复合值从函数中返回
func minMax(arrayA:[Int]) -> (minA:Int, maxA:Int)? {
if arrayA.isEmpty {
return nil
}
var min = arrayA[0]
var max = arrayA[0]
for item in arrayA {
if item < min {
min = item
} else if (max < item) {
max = item
}
}
return (min, max)
}
let minArray:[Int] = [1,6,8,3,12,45,78,0]
let valueArrayy = minMax(minArray)!
print("数组arrayA中 min : ", valueArrayy.minA, "\n", "数组arrayA中 max: ", valueArrayy.maxA)
print("min : \(valueArrayy.minA) , max : \(valueArrayy.maxA)")
// 可选元组类型 如(Int, Int)?与元组包含可选类型如(Int?, Int?)是不同的.可选的元组类型,整个元组是可选的,而不只是元组中的每个元素值。
// (6)没有返回值函数 :
func readMyName(myName:String) {
print(myName)
}
readMyName("phoebe_zhangxiaoping...")
// (7)函数参数名称 : 函数参数都有一个外部参数名和一个局部参数名
/**
局部参数名称 : 在函数内部使用 , (例如 myName为局部参数名,只能在函数体内使用
外部参数名称 : 可以在局部参数名前指定外部参数名,中间以空格分隔,外部参数名用于在函数调用时传递给函数的参数
*/
func readName(name myName: String, nickName myNickmane: String) {
print(myName, myNickmane)
}
readName(name: "zhangxiaoping", nickName: "phoebe")
// (8)可变参数 : 可变参数可以接受零个或多个值。函数调用时,你可以用可变参数来指定函数参数,其数量是不确定的
// 可变参数通过在变量类型名后面加入(...)的方式来定义
func readNickName(yourNicknam: String...) {
print(yourNicknam)
}
readNickName("你的昵称 ", "Phoebe", "nickname") // 输出 : ["你的昵称 ", "Phoebe", "nickname"]
// (9)常量,变量及I/O参数
// 一般默认在函数中定义的参数都是常量参数,也就是这个参数你只可以查询使用,不能改变它的值
// 一般默认的参数传递都是传值调用的,而不是传引用。 所以传入的参数在函数内改变,并不影响原来的那个参数。传入的只是这个参数的副本
/**
(* swift 3 中要删除此方法) func getName(var id:String)....... : 如果想要声明一个变量参数,可以在前面加上var,这样就可以改变这个参数的值了
inout 关键字 : In-Out Parameters 输入输出参数,如果你想要一个函数可以修改参数的值,且想要在这些修改在函数调用结束后仍然存在,则定义为输入输出参数
*/
/** swift 3 中将要删除此方法
func addAB(var a:Int, var b:Int) {
a *= 2
b *= 2
print("\(a) * \(b) = \(a*b)")
}
addAB(10, b: 10)
*/
var inoutA = 10
var inoutB = 20
func inoutAB( a:inout Int, b:inout Int) {
a *= 2
b *= 2
let c = a + b
print("a*2 + b*2 = \(c)")
}
print("原始值:",inoutA, inoutB)
inoutAB(&inoutA, b: &inoutB)
print("改变后:", inoutA, inoutB)
// (10)函数类型及使用 : 每个函数都有种特定的函数类型,由函数的参数类型和返回类型组成
// 使用函数类型 : 你可以定义一个类型为函数的常量或变量,并将适当的函数赋值给它
/**
var addition: (Int, Int) -> Int = sum
解析 : 定义一个叫addition的变量,参数与返回的类型均为Int, 并让这个新变量指向sum函数。
sum 和 addition 有同样的类型,所以以上操作是合法的
*/
func sum(a: Int, b: Int) -> Int {
return a+b
}
let addAABB:(Int, Int) -> Int = sum
print(addAABB(10,20))
// (11)函数类型作为参数类型、函数类型作为返回类型 :
// 可以将函数作为参数传递给另外一个参数
func subA(a: Int, b: Int) -> Int {
return a-b
}
// var subB:(Int, Int) -> Int = subA
let subB = subA
print("20 - 10 = ", subB(20,b: 10))
func subC(subA: (_ a: Int, _ b: Int)->Int, c: Int, d: Int) {
print("30 - 20 = ", subA(a: c, b: d))
}
subC(subA, c: 30, d: 20)
// (12)函数嵌套 : 函数嵌套指的是函数内定义一个新的函数,外部的函数可以调用函数内定义的函数
func nestA(a: Int, b: Int) -> Int {
func nestB(c: Int)->Int {
return c*2
}
let d = nestB(10)
print("d = \(d)")
return nestB(a) + nestB(b)
}
let e = nestA(10, b: 20)
print("eeeeeeee ====== \(e)")
//
//
/**
它声明在类中,可以通过实例化类来访问它的值。
枚举也可以定义构造函数(initializers)来提供一个初始成员值;可以在原始的实现基础上扩展它们的功能。
可以遵守协议(protocols)来提供标准的功能
enum enumname {
// 枚举定义放在这里
}
* 注意 : Swift 的枚举成员在被创建时不会被赋予一个默认的整型值
*/
// (1)语法 :
var weekDay = DayssofaWeek.WEDNESDAY
weekDay = .WEDNESDAY
switch weekDay {
case .Sunday:
print("周日")
case .WEDNESDAY:
print("周三")
default:
print("周六")
}
// (2)相关值 : 以下实例中定义一个名为 Student 的枚举类型,它可以是 Name 的一个相关值(Int,Int,Int),或者是 Mark 的一个字符串类型(String)相关值
let stuNames = Student.Name("ZhangSan")
let stuMarks = Student.Mark(98, 97, 95)
switch stuMarks {
case .Name(let stuName):
print("学生的名字是: \(stuName)")
case .Mark(let Mark1, let Mark2, let Mark3):
print("学生的成绩是: \(Mark1), \(Mark2), \(Mark3)")
} // 输出结果 : 学生的成绩是: 98,97,95
print(stuNames)
// 原始值 : 原始值可以是字符串,字符,或者任何整型值或浮点型值
// 在原始值为整数的枚举时,不需要显式的为每一个成员赋值,Swift会自动为你赋值。
// 例如,当使用整数作为原始值时,隐式赋值的值依次递增1。如果第一个值没有被赋初值,将会被自动置为0
/**
enum Month: Int {
case January = 1, February, March, April, May, June, July, August, September, October, November, December
}
*/
let weekday1 = DayssofaWeek.WEDNESDAY.hashValue
print(weekday1) // 输出: 3
//
// 可以为结构体定义属性(常量、变量)和添加方法,从而扩展结构体的功能
/** 区别于C和OC:
结构体不需要包含实现文件和接口。
结构体允许我们创建一个单一文件,且系统会自动生成面向其它代码的外部接口。
*/
// 结构体总是通过被复制的方式在代码中传递,因此它的值是不可修改的
// (1)语法 : 关键字 struct
/**
struct nameStruct {
Definition 1
Definition 2
……
Definition N
}
*/
struct sturentsMarksStruct {
var English:Int = 100
var Chines:Int = 99
var math:Int = 98
}
// 我们可以通过结构体名来访问结构体成员。结构体实例化使用 let 关键字:
let myMarks = sturentsMarksStruct()
print("我的成绩是:", myMarks.English, myMarks.math, myMarks.Chines)
// 以下实例化通过结构体实例化时传值并克隆一个结构体
struct YourMarksStruct {
var mark : Int
init(mark: Int) {
self.mark = mark
}
}
var aStruct = YourMarksStruct(mark: 99)
aStruct.mark = 100
var bStruct = aStruct
bStruct.mark = 97
print(aStruct.mark, bStruct.mark) // 100, 97
// (2)结构体应用 :
// 结构体实例总是通过值传递来定义你的自定义数据类型
/** 按照通用的准则,当符合一条或多条以下条件时,请考虑构建结构体:
结构体的主要目的是用来封装少量相关简单数据值。
有理由预计一个结构体实例在赋值或传递时,封装的数据将会被拷贝而不是被引用。
任何在结构体中储存的值类型属性,也将会被拷贝,而不是被引用。
结构体不需要去继承另一个已存在类型的属性或者行为。
*/
// 结构体实例是通过值传递而不是通过引用传递
//
// (1)类与结构体对比
/** 与结构体相比,类还有如下的附加功能:
继承允许一个类继承另一个类的特征
类型转换允许在运行时检查和解释一个类实例的类型
解构器允许一个类实例释放任何其所被分配的资源
引用计数允许对一个类的多次引用
*/
/** 语法 :
Class classname {
Definition 1
Definition 2
……
Definition N
}
*/
// (2)作为引用类型访问类属性 : 类的属性可以通过 . 来访问。格式为:实例化类名.属性名
// (3)恒等运算符 :
// 因为类是引用类型,有可能有多个常量和变量在后台同时引用某一个类实例。
/** 为了能够判定两个常量或者变量是否引用同一个类实例,Swift 内建了两个恒等运算符:
恒等运算符 不恒等运算符
运算符为:=== 运算符为:!==
如果两个常量或者变量引用同一个类实例则返回 true 如果两个常量或者变量引用不同一个类实例则返回 true
*/
//
// Swift 属性将值跟特定的类、结构或枚举关联。 属性可分为存储属性和计算属性
/**
存储属性 计算属性
存储常量或变量作为实例的一部分 计算(而不是存储)一个值
用于类和结构体 用于类、结构体和枚举
*/
// (1)存储属性 : 简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量。
// (2)延迟存储属性 : 延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用 lazy 来标示一个延迟存储属性。
/**
* 注意:
必须将延迟存储属性声明成变量(使用var关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
*/
// (3)实例化变量 : 一个类型中属性的全部信息——包括命名、类型和内存管理特征——都在唯一一个地方(类型定义中)定义。
// (4)计算属性 : 除存储属性外,类、结构体和枚举可以定义计算属性,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值
// (5)只读计算属性 : 只有 getter 没有 setter 的计算属性就是只读计算属性
// 必须使用var关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。let关键字只用来声明常量属性,表示初始化后再也无法修改的值。
// (6)属性观察器 : 属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,甚至新的值和现在的值相同的时候也不例外。
// (7)全局变量和局部变量 : 计算属性和属性观察器所描述的模式也可以用于全局变量和局部变量
/**
局部变量 全局变量
在函数、方法或闭包内部定义的变量。 函数、方法、闭包或任何类型之外定义的变量。
用于存储和检索值。 用于存储和检索值。
存储属性用于获取和设置值。 存储属性用于获取和设置值。
也用于计算属性。 也用于计算属性。
*/
// (8)类型属性 : 类型属性是作为类型定义的一部分写在类型最外层的花括号({})内。
// 使用关键字 static 来定义值类型的类型属性,关键字 class 来为类定义类型属性。
struct Teachers {
static var English = ""
static var computedTypeProperty:Int {
return 3
}
}
enum TYpessss {
static var TypeAA = ""
static var TypeBB:Int {
return 3
}
func typeDid(a:Int) -> Int {
print(">>>>>> 枚举中定义方法:", a)
return a*2
}
}
class CLASSsss {
class var classAAA: Int {
return 3
}
}
// (9)获取和设置类型属性的值 : 类似于实例的属性,类型属性的访问也是通过点运算符(.)来进行。但是,类型属性是通过类型本身来获取和设置,而不是通过实例
//
//
// Swift 方法是与某些特定类型相关联的函数
// 在 Objective-C 中,类是唯一能定义方法的类型。但在 Swift 中,你不仅能选择是否要定义一个类/结构体/枚举,还能灵活的在你创建的类型(类/结构体/枚举)上定义方法。
// (1)实例方法 :
/** 语法 :
func <#name#>(<#parameters#>) -> <#return type#> {
<#function body#>
}
*/
print(aAddB(100, b: 200))
countADD(100)
print(countA)
// 方法的局部参数名称和外部参数名称 : Swift 默认仅给方法的第一个参数名称一个局部参数名称;默认同时给第二个和后续的参数名称为全局参数名称
// 例如 aAddB 方法中,a 为局部参数名称, b 用于全局的声明并通过外部程序访问。
// 是否提供外部名称设置 : 我们强制在第一个参数添加外部名称把这个局部名称当作外部名称使用(Swift 2.0前是使用 # 号)。
// 相反,我们呢也可以使用下划线(_)设置第二个及后续的参数不提供一个外部名称
func paramA(first a:Int, b:Int) {
print("\(a+b)")
}
paramA(first: 10, b: 10)
func paramB(a:Int, second _b:Int) {
print("\(a-_b)")
}
paramB(10, second: 5)
// (2)self 属性 : 类型的每一个实例都有一个隐含属性叫做self,self 完全等同于该实例本身。
// 你可以在一个实例的实例方法中使用这个隐含的self属性来引用当前实例。
self.countA = 100
print(self.countA)
// (3)在实例方法中修改值类型 : 变异(mutating)
/**
Swift 语言中结构体和枚举是值类型。一般情况下,值类型的属性不能在它的实例方法中被修改。
但是,如果你确实需要在某个具体的方法中修改结构体或者枚举的属性,你可以选择变异(mutating)这个方法,然后方法就可以从方法内部改变它的属性;并且它做的任何改变在方法结束时还会保留在原始结构中。
方法还可以给它隐含的self属性赋值一个全新的实例,这个新实例在方法结束后将替换原来的实例。
*/
var mutaMarks = MarkStruct(English: 99, Chines: 99, Math: 95)
print(">>>>> 英语 : ", mutaMarks.English)
mutaMarks.subMarks(100, math: 90)
print(">>>>> 英语...... : ", mutaMarks.English)
// (4)在可变方法中给self赋值 : 可变方法能够赋给隐含属性 self 一个全新的实例。 mutating
// (5)类型方法 : 实例方法是被类型的某个实例调用的方法,你也可以定义类型本身调用的方法
// 声明结构体和枚举的类型方法,在方法的func关键字之前加上关键字static。 static
// 类可能会用关键字class来允许子类重写父类的实现方法。 class
// 类型方法和实例方法一样用点号(.)语法调用
let minmarkss = MarkStruct.minMarks(90, math: 80)
print(minmarkss)
//
// class关键字除了有自定义类的作用, 还有声明类方法的作用
// (1)在方法的func关键字之前加上关键字static或者class都可以用于指定类方法.
// (2)不同的是用class关键字指定的类方法可以被子类重写, 但是用static关键字指定的类方法是不能被子类重写的
// (3)类方法和实例方法可以重名
//
/**
下标脚本 可以定义在类(Class)、结构体(structure)和枚举(enumeration)这些目标中,可以认为是访问对象、集合或序列的快捷方式,不需要再调用实例的特定的赋值和访问方法。
举例来说,用下标脚本访问一个数组(Array)实例中的元素可以这样写 someArray[index] ,访问字典(Dictionary)实例中的元素可以这样写 someDictionary[key]。
对于同一个目标可以定义多个下标脚本,通过索引值类型的不同来进行重载,而且索引值的个数可以是多个
*/
// (1)下标脚本语法及应用 :
/** 语法 :
subscript(index: Int) -> Int {
get {
// 用于下标脚本值的声明
}
set(newValue) {
// 执行赋值操作
}
}
*/
let subscriMark = MarkStruct(English: 100, Chines: 100, Math: 100)
print("100/10 = ", subscriMark[10])
print("100/20 = ", subscriMark[20])
let p = ViewController2()
print(p[0],"\n")
// 用法 : 通常下标脚本是用来访问集合(collection),列表(list)或序列(sequence)中元素的快捷方式。
// 你可以在你自己特定的类或结构体中自由的实现下标脚本来提供合适的功能
// (2)下标脚本选项 :
/**
下标脚本允许任意数量的入参索引,并且每个入参类型也没有限制。
下标脚本的返回值也可以是任何类型。
下标脚本可以使用变量参数和可变参数。
一个类或结构体可以根据自身需要提供多个下标脚本实现,在定义下标脚本时通过传入参数的类型进行区分,使用下标脚本时会自动匹配合适的下标脚本实现运行,这就是下标脚本的重载。
*/
print("下标脚本重载: 10*2+2 = ",subscriMark[10,2])
//
// 子类, 超类(或父类)
// 在 Swift 中,类可以调用和访问超类的方法,属性和下标脚本,并且可以重写它们。
// (1)基类 : 没有继承其它类的类,称之为基类(Base Class)
// (2)子类 : 子类指的是在一个已有类的基础上创建一个新的类
// (3)重写 : Overriding, 子类可以通过继承来的实例方法,类方法,实例属性,或下标脚本来实现自己的定制功能,我们把这种行为叫重写
/**
重写 访问方法,属性,下标脚本
方法 super.somemethod()
属性 super.someProperty()
下标脚本 super[someIndex]
*/
// (4)重写方法和属性 :
// 重写方法 :
let superStudent = StudentDetails()
superStudent.recordMarks()
let subTom = Tom()
subTom.recordMarks()
// 重写属性 : 你可以提供定制的 getter(或 setter)来重写任意继承来的属性,无论继承来的属性是存储型的还是计算型的属性
/** 注意
如果你在重写属性中提供了 setter,那么你也一定要提供 getter。
如果你不想在重写版本中的 getter 里修改继承来的属性值,你可以直接通过super.someProperty来返回继承来的值,其中someProperty是你要重写的属性的名字。
*/
subTom.English = 100
//subTom.Math = 120 // get-only
print("重写属性:tom ", subTom.Math)
// (5)重写属性观察器 : 你可以在属性重写中为一个继承来的属性添加属性观察器。这样一来,当继承来的属性值发生改变时,你就会监测到。
// 注意:你不可以为继承来的常量存储型属性或继承来的只读计算型属性添加属性观察器。
subTom.English = 200
print(">>>> 重写:", subTom.Chines, subTom.Math)
// (6)防止重写 : final, 我们可以使用 final 关键字防止它们被重写
// 如果你重写了final方法,属性或下标脚本,在编译时会报错。
// 你可以通过在关键字class前添加final特性(final class)来将整个类标记为 final 的,这样的类是不可被继承的,否则会报编译错误。
// 构造过程是为了使用某个类、结构体或枚举类型的实例而进行的准备过程。这个过程包含了为实例中的每个属性设置初始值和为其执行必要的准备和初始化任务
// 构造函数 : init() , 与Object-C中的构造器不同, swift的构造函数无需返回值, 它们的主要任务是保证新实例在第一次使用前完成正确的初始化
// 类实例也可以通过定义析构器(deinitializer)在类实例释放之前执行清理内存的工作。
// (1)存储型属性的初始赋值 : 在实例创建时,必须为所有存储型属性设置合适的初始值。
// 存储属性在构造器中赋值时,它们的值是被直接设置的,不会触发任何属性观测器。
/** 存储属性在构造器中赋值流程:
创建初始值。
在属性定义中指定默认属性值。
初始化实例,并调用 init() 方法。
*/
// (2)构造器 : init 构造器在创建某特定类型的新实例时调用。它的最简形式类似于一个不带任何参数的实例方法,以关键字init命名。
/** 语法 :
init() {
// 实例化后执行的代码
}
*/
//实例 : 以下结构体定义了一个不带参数的构造器 init,并在里面将存储型属性 length 和 breadth 的值初始化为 6 和 12:
struct AinitaStruct {
var length:Double
var width:Double
var r = 3.5 // (3)默认属性值
init() {
length = 5.5
width = 9
}
}
let areaA = AinitaStruct()
print("矩形的面积:\(areaA.length * areaA.width)")
// (3)默认属性值 : 我们可以在构造器中为存储型属性设置初始值;同样,也可以在属性声明时为其设置默认值。
// 使用默认值能让你的构造器更简洁、更清晰,且能通过默认值自动推导出属性的类型。
// (4)构造参数 : 你可以在定义构造器 init() 时提供构造参数,如下所示:
struct AparamStruct {
var length : Double
var width : Double
var area : Double
init(fromLength length: Double, fromWidth width: Double) {
self.length = length
self.width = width
area = length * width
}
init(fromLg lg: Double, fromWd wd: Double) {
self.length = lg
self.width = wd
area = lg * wd
}
}
let areaPA = AparamStruct(fromLength: 10, fromWidth: 20)
let areaPB = AparamStruct(fromLg: 100, fromWd: 200)
let areaPC = AparamStruct.init(fromLength: 5, fromWidth: 10)
print("areaPA:\(areaPA.area), areaPB:\(areaPB.area), areaPC:\(areaPC)")
// (5)内部和外部参数名 : 如果你在定义构造器时没有提供参数的外部名字,Swift 会为每个构造器的参数自动生成一个跟内部名字相同的外部名。
struct Color {
let red, green, blue: Double
init (red: Double, green: Double, blue: Double) {
self.red = red
self.green = green
self.blue = blue
}
init(white: Double) {
red = white
green = white
blue = white
}
}
let purpleColor = Color.init(red: 255, green: 222, blue: 111)
let yellowColor = Color.init(white: 200)
print(purpleColor.red, yellowColor.red)
// 没有外部参数名称 : 如果你不希望为构造器的某个参数提供外部名字,你可以使用下划线_来显示描述它的外部名
struct ColorNO {
let red: Double
init(_ white: Double) {
red = white
}
}
let noColorA = ColorNO.init(100)
print(">>>>>>>> 没有外物参数: noColorA = ", noColorA.red)
// (6)可选属性类型 : 如果你定制的类型包含一个逻辑上允许取值为空的存储型属性,你都需要将它定义为可选类型optional type(可选属性类型)。
// 当存储属性声明为可选时,将自动初始化为空 nil
struct RGB {
var red : Double?
let green : Double? // (7)green属性现在是常量
init(white: Double) {
red = white + 10
green = red! + 10 // (7)仍然可以在构造器中设置值
}
init(_ black: Double) {
red = black
green = red! + 100
}
}
let RGBa = RGB.init(white: 100)
let RGBb = RGB.init(200)
// print(RGBa.red, RGBb.red) // 输出结果 Optional(110.0) Optional(200.0)
print(RGBa.red!, RGBb.red!) // 输出结果 110.0 200.0
// (7)构造过程中修改常量属性 : 只要在构造过程结束前常量的值能确定,你可以在构造过程中的任意时间点修改常量属性的值
// 对某个类实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改
// (8)默认构造器 : 默认构造器将简单的创建一个所有属性值都设置为默认值的实例
// 以下实例中,ShoppingListItem类中的所有属性都有默认值,且它是没有父类的基类,它将自动获得一个可以为所有属性设置默认值的默认构造器
let item = ShoppingListItem()
print("默认构造器: ", item.name, item.quantity, item.purchased) // 输出结果: 默认构造器: nil 1 false
// 结构体的逐一成员构造器 : 如果结构体对所有存储型属性提供了默认值且自身没有提供定制的构造器,它们能自动获得一个逐一成员构造器。
// 我们在调用逐一成员构造器时,通过与成员属性名相同的参数名进行传值来完成对成员属性的初始赋值。
struct Shopping {
var length = 100.0
var width = 200.0
}
let shopA = Shopping.init(length: 33.0, width: 24.0)
print("结构体的逐一成员变量: ", shopA.length*shopA.width)
// (9)值类型的构造器代理 : 构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为构造器代理,它能减少多个构造器间的代码重复。
// 以下实例中,RectA 结构体调用了 SizeA 和 PointA 的构造过程:
struct SizeA {
var width = 0.0, height = 0.0
}
struct PointA {
var x = 0.0, y = 0.0
}
struct RectA {
var origin = PointA() // origin属性使用定义时的默认值PointA(x: 0.0, y: 0.0)
var size = SizeA()
init() {}
init(origin: PointA, size: SizeA) {
self.origin = origin
self.size = size
}
init(center: PointA, size: SizeA) {
//先通过center和size的值计算出origin的坐标
let originX = center.x - size.width/2
let originY = center.y - size.height/2
//然后再调用(或代理给)init(origin:size:)构造器来将新的origin和size值赋值到对应的属性中
self.init(origin: PointA.init(x: originX, y: originY), size: size)
}
}
let rectA = RectA()
print("PointA 结构体初始值: \(rectA.origin.x, rectA.origin.y)") // 输出结果 : PointA 结构体初始值: (0.0, 0.0)
// 将origin和size的参数值赋给对应的存储型属性
let rectB = RectA.init(origin: PointA(x: 56.0, y: 45.0), size: SizeA(width: 100.0, height: 200.0))
print("PointB 结构体初始值: \(rectB.origin.x, rectB.origin.y)") // 输出结果 : PointB 结构体初始值: (56.0, 45.0)
//先通过center和size的值计算出origin的坐标。
//然后再调用(或代理给)init(origin:size:)构造器来将新的origin和size值赋值到对应的属性中
let rectC = RectA.init(center: PointA(x: 10.0, y: 10.0), size: SizeA(width: 24.0, height: 25.0))
print("PointC 结构体初始值: \(rectC.origin.x, rectC.origin.y)") // 输出结果 : PointC 结构体初始值: (-2.0, -2.5)
/** 构造器代理规则 :
值类型 : 不支持继承,所以构造器代理的过程相对简单,因为它们只能代理给本身提供的其它构造器。 可以使用self.init在自定义的构造器中引用其它的属于相同值类型的构造器。
类类型 : 它可以继承自其它类,这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。
*/
// (10)类的继承和构造过程 : Swift 提供了两种类型的类构造器来确保所有类实例中 存储型属性 都能获得初始值,它们分别是指定构造器和便利构造器。
/**
指定构造器 : 类中最主要的构造器
初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化。
每一个类都必须拥有至少一个指定构造器
Init(parameters) {
statements
}
便利构造器 : 类中比较次要的、辅助型的构造器
可以定义便利构造器来调用同一个类中的指定构造器,并为其参数提供默认值。你也可以定义便利构造器来创建一个特殊用途或特定输入的实例。
只在必要的时候为类提供便利构造器
convenience init(parameters) {
statements
}
*/
let yuebing = Mooncake.init(huaMei: "华美月饼")
let yuebing1 = Ronglang.init(huaMei: "华美月饼", rongLang: "荣朗月饼")
print(">>>> 华美: \(yuebing.huamei), \n, >>>>> 华美: \(yuebing1.huamei), \n, >>>>> 荣朗: \(yuebing1.ronglang)")
let car = carCalss(aoDI: "奥迪。。。")
// let aodi = AODIClass(aoDI: "奥迪、、、", daZhong: "大众、、、")
let aodi = AODIClass.init(aoDI: "奥迪")
print("car: \(car.aodi) \n AODI: \(aodi.aodi, aodi.dazhong)")
// (11)构造器的继承和重载 : Swift 中的子类不会默认继承父类的构造器
// 父类的构造器仅在确定和安全的情况下被继承。 当你重写一个父类指定构造器时,你需要写override修饰符。
let wine = WineClass()
print(wine.desccription) // 输出结果 : 红酒 不错!
let redwine = REDWineClass()
print(redwine.desccription) // 输出结果 : 红酒名酒。。。 不错!
// 指定构造器和便利构造器实例 : 接下来的例子将在操作中展示指定构造器、便利构造器和自动构造器的继承。
// 它定义了包含两个个类MainClass、SubClass的类层次结构,并将演示它们的构造器是如何相互作用的。
let game = GameClass(mobilegame: "精灵宝")
print("game : \(game.mobileGames)") // 输出结果: game : 精灵宝
let game1 = GameClass()
print("game none : \(game1.mobileGames)") // 输出结果: game none : 逐鹿天下手游
let mobile = MobileGameClass.init(mobilegame: "纪念碑谷")
print("mobile one : \(mobile.mobileGames)") // 输出结果: mobile one : 纪念碑谷
let mobile1 = MobileGameClass.init(moblegame: "梦幻西游", zhulu: "酷跑")
print("mobile1 two : \(mobile1.zhuluGame)") // 输出结果: mobile1 two : 酷跑
// (12)类的可失败构造器 : 如果一个类,结构体或枚举类型的对象,在构造自身的过程中有可能失败,则为其定义一个可失败构造器。
// 其语法为在init关键字后面加添问号(init?)
/** 变量初始化失败可能的原因有:
传入无效的参数值。
缺少某种所需的外部资源。
没有满足特定条件。
*/
struct GameStruct {
let game: String
init?(zhulu: String) {
if zhulu.isEmpty {
return nil
} else {
self.game = zhulu
}
}
}
//通过该可失败构造器来构建一个GameStruct的对象,并检查其构建过程是否成功
// gameZhulu 的类型是 GameStruct? 而不是 GameStruct
let gameZhulu = GameStruct.init(zhulu: "逐鹿天下,》》》")
if let zhulu = gameZhulu {
print("可失败构造器: \(zhulu.game)")
}
// 枚举类型的可失败构造器
// (13)覆盖一个可失败构造器
// 就如同其它构造器一样,你也可以用子类的可失败构造器覆盖基类的可失败构造器。
// 者你也可以用子类的非可失败构造器覆盖一个基类的可失败构造器。
// 你可以用一个非可失败构造器覆盖一个可失败构造器,但反过来却行不通。
// 一个非可失败的构造器永远也不能代理调用一个可失败构造器。
let plName = planet(name: "Mercury")
print("行星的名字是:\(plName.name)") // 行星的名字是: Mercury
let nopName = planet()
print("没有这个星星的名字:\(nopName.name)") // 没有这个名字的行星: [No Planets]
// (14)可失败构造器 init!
// 通常来说我们通过在init关键字后添加问号的方式(init?)来定义一个可失败构造器,但你也可以使用通过在init后面添加惊叹号的方式来定义一个可失败构造器(init!)
let stmaek = StuRecord(stname: "Runoob")
if let name = stmaek {
print("指定了学生名:\(name)") // 指定了学生名:
}
let blankname = StuRecord(stname: "")
if blankname == nil {
print("学生名为空") // 学生名为空
}
//
// deinit : 在一个类的实例被释放之前,析构函数被立即调用。用关键字deinit来标示析构函数,类似于初始化函数用init来标示。析构函数只适用于类类型。
/** 析构过程原理 :
Swift 会自动释放不再需要的实例以释放资源。
Swift 通过自动引用计数(ARC)处理实例的内存管理。
通常当你的实例被释放时不需要手动地去清理。但是,当使用自己的资源时,你可能需要进行一些额外的清理。
例如,如果创建了一个自定义的类来打开一个文件,并写入一些数据,你可能需要在类实例被释放之前关闭该文件。
*/
/** 语法 : 在类的定义中,每个类最多只能有一个析构函数。析构函数不带任何参数,在写法上不带括号:
deinit {
// 执行析构过程
}
*/
var show: BaseClass? = BaseClass()
var hide: BaseClass? = BaseClass.init()
print("有值: ", counter) // 输出: 有值: 2
show = nil // 当show = nil 语句执行后,计算器减1,show占用的内存就会释放。
hide = nil
print("置空:", counter) // 输出: 置空: 0
print(show, hide) // 输出: nil nil
//
// ARC 这一机制跟踪和管理应用程序的内存。 通常不需要手动释放内存,因为 ARC 会在类的实例不再被使用时,自动释放其占用的内存
/** ARC 功能:
init() , 当每次使用 init() 方法创建一个类的新的实例的时候,ARC 会分配一大块内存用来储存实例的信息。
内存中包含实例的类型信息, 以及这个实例所有相关属性的值
当实例不再被使用时,ARC 释放实例所占用的内存,并让释放的内存能挪作他用。
为了确保使用中的实例不会被销毁,ARC 会跟踪和计算每一个实例正在被多少属性,常量和变量所引用。
实例赋值给属性、常量或变量,它们都会创建此实例的强引用,只要强引用还在,实例是不允许被销毁的。
*/
// 值会被自动初始化为nil, 目前还不会引用到BaseClass类的实例
var baseC : BaseClass?
var baseC1 : BaseClass?
var baseC2 : BaseClass?
// 创建BaseClass类的实例
baseC = BaseClass()
// 赋值给其他两个变量,该实例又会多出两个强引用
baseC1 = baseC
baseC2 = baseC
// 断开第一个强引用
baseC = nil
// 断开第二个强引用
baseC1 = nil
// 断开第三个强引用,并调用析构函数
baseC2 = nil
print(baseC1, baseC2)
// 在上面的例子中,ARC 会跟踪你所新创建的 BaseClass 实例的引用数量,并且会在 BaseClass 实例不再被需要时销毁它
// *** 类实例之间的循环强引用
// *** 类实例之间的循环强引用
// 一个类永远不会有0个强引用,这种情况发生在两个类实例相互保持对方的强引用,并让对方不被销毁,这就是所谓的循环强引用
// 两个变量都被初始化为nil
var basesingcalss : SignClass?
var basessclass : SSClass?
// 赋值
basesingcalss = SignClass.init(name: "BaseSignClass")
basessclass = SSClass.init(number: 73)
// 意感叹号是用来展开和访问可选变量 runoob 和 number73 中的实例
// 循环强引用被创建
basesingcalss!.baseSs = basessclass
basessclass!.baseSign = basesingcalss
// 断开basesingcalss 和 basessclass 变量所持有的强引用时,引用计数并不会降为0, 实例也不会被 ARC 销毁
// 注意, 当你把这两个变量设置为nil时,没有任何一个析构函数被调用
// 强引用循环阻止了SignClass,SSClass类实例的销毁, 并在你的应用程序中造成了内存泄露
basesingcalss = nil
basessclass = nil
print("循环请引用", basesingcalss, basessclass)
// 解决实例之间的循环强引用 : weak 弱引用, unowned 无主引用
// 此两种引用允许循环引用中的一个实例引用另外一个实例而不保持强引用,这样实例能够相互引用而不产生循环强引用
// 对于生命周期中会变为nil的实例使用弱引用,相反的, 对于初始化赋值后再也不会被赋值为nil的实例, 使用无主引用。
// 弱引用实例
var toc : Module?
var list : SubModul?
toc = Module.init(name: "ARC")
list = SubModul.init(number: 4)
toc!.sub = list
list!.topic = toc
toc = nil
list = nil
print("弱引用", basesingcalss, basessclass)
// 无主引用实例
var peter : StudentPeter?
peter = StudentPeter.init(name: "Peter")
peter!.section = MarkPeter.init(marks: 99, stname: peter!)
peter = nil
// *** 闭包引起的循环强引用
// *** 闭包引起的循环强引用
// 当你将一个闭包赋值给类实例的某个属性, 并且这个闭包体中又使用了实例。这个闭包体中可能访问了实例的某个属性,例如self.someProperty, 或者闭包中调用了实例的某个方法,例如self.someMethod。 这两种情况导致了闭包“捕获”self, 从而产生了循环引用。
// 创建实例并打印信息
var paragraph: HTMLElement?
paragraph = HTMLElement.init(name: "pp", text: "hellow, world")
// print(paragraph!.asHTML)
// 解决闭包引起的循环强引用 : 在定义闭包时同时定义捕获列表作为闭包的一部分,通过这种方式可以解决闭包和类实例之间的循环强引用
/** 弱引用和无主引用
当闭包和捕获的实例总是互相引用时并且总是同时销毁时,将闭包内的捕获定义为无主引用。
相反的,当捕获引用有时可能会是nil时,将闭包内的捕获定义为弱引用。
如果捕获的引用绝对不会置为nil,应该用无主引用,而不是弱引用。
*/
print(paragraph!.asasHTML())
// HTMLElement实例将会被销毁,并能看到它的析构函数打印出的消息
paragraph = nil
//
/** 检测 is, 转换 as
Swift 语言类型转换可以判断实例的类型。也可以用于检测实例类型是否属于其父类或者子类的实例。
Swift 中类型转换使用 is 和 as 操作符实现,is 用于检测值的类型,as 用于转换类型。
类型转换也可以用来检查一个类是否实现了某个协议。
*/
// (1)定义一个类层次
// 类型转换用于检测实例类型是否属于特定的实例类型
// 你可以将它用在类和子类的层次结构上,检查特定类实例的类型并且转换这个类实例的类型成为这个层次结构中的其他类型。
class Subjects {
var physics : String
init(physics : String) {
self.physics = physics
}
}
class Chemistry : Subjects {
var equations : String
init(physics: String, equations: String) {
self.equations = equations
super.init(physics: physics)
}
}
class Maths: Subjects {
var formulae : String
init(physics : String, formulae : String) {
self.formulae = formulae
super.init(physics: physics)
}
}
let sa = [Chemistry(physics: "固体物理", equations: "赫兹"),
Maths(physics: "流体动力学", formulae: "千兆赫"),
Maths(physics: "流体动力学", formulae: "千兆赫"),]
let samplechem = Chemistry.init(physics: "固体物理", equations: "赫兹")
print("实例物理学史: \(samplechem.physics)")
print("实例方程式: \(samplechem.equations) \(sa[0].physics)")
let samplemaths = Maths(physics: "流体动力学", formulae: "千兆赫")
print("实例物理学是: \(samplemaths.physics)")
print("实例公式是: \(samplemaths.formulae)")
// (2)检查类型 : 关键字 is
// 操作符 is 来检查一个实例是否属于特定子类型。若实例属于那个子类型,类型检查操作符返回 true,否则返回 false。
var chemCount = 0
var mathsCount = 0
for item in sa {
if item is Chemistry {
chemCount += 1
} else {
mathsCount += 1
}
}
print("化学科目包含: \(chemCount)个, 数学包含: \(mathsCount)个主题") // 化学科目包含: 1个, 数学包含: 2个主题
// (3)向下转型 : as? 或 as!
// as? 当你不确定向下转型可以成功时,用类型转换的条件形式(as?)。条件形式的类型转换总是返回一个可选值(optional value),并且若下转是不可能的,可选值将是 nil。
// as! 只有你可以确定向下转型一定会成功时,才使用强制形式(as!)。当你试图向下转型为一个不正确的类型时,强制形式的类型转换会触发一个运行时错误。
for item in sa {
// 类型转换的条件形式
if let show = item as? Chemistry {
print("化学主题是: '\(show.physics)', \(show.equations)")
// 强制形式
} else if let example = item as? Maths {
print("数学主题是: '\(example.physics)', \(example.formulae)")
}
}
// (4)Any 和 AnyObject的类型转换
// AnyObject : 可以代表任何class类型的实例 , Any 可以代表任何类型,包括方法类(function types)
// 注意: 只有当你明确的需要它的行为和功能时才使用Any和AnyObject。在你的代码里使用你期望的明确的类型总是更好的
// Any 实例 :
// 可以存储Any类型的数组 exampleany
var exampleany = [Any]()
exampleany.append(12)
exampleany.append(3.14159)
exampleany.append("Any 实例")
exampleany.append(Chemistry(physics: "固体物理", equations: "赫兹"))
for item in exampleany {
switch item {
case let someInt as Int :
print("整型值为 \(someInt)")
case let someDouble as Double :
print("Pi 值为 \(someDouble)")
case let someString as String :
print("\(someString)")
case let phy as Chemistry:
print("主题 '\(phy.physics)', \(phy.equations)")
default:
print("None")
}
}
// AnyObject 实例
let saprint : [AnyObject] = [Chemistry.init(physics: "11", equations: "aa"),
Maths.init(physics: "22", formulae: "bb"),
Chemistry.init(physics: "33", equations: "cc"),
Maths.init(physics: "44", formulae: "dd")]
for item in saprint {
// 类型转换的条件形式
if let show = item as? Chemistry {
print("化学主题是: '\(show.physics)', \(show.equations)")
// 强制形式
} else if let example = item as? Maths {
print("数学主题是: '\(example.physics)', \(example.formulae)")
}
}
//
// 扩展就是向一个已有的类、结构体或枚举类型添加新的功能
// 扩展可以对一个已有的类型添加新的功能, 但是不能重写已有的功能
/** swift中的扩展可以:
添加计算型属性和计算型静态属性
定义实例方法和类型方法
提供新的构造器
定义下标
定义和使用新的嵌套类型
使一个已有类型符合某个协议
*/
/** 语法 : 关键字 extension
extension SomeType {
// 加到SomeType的新功能写在这里
}
一个扩展可以扩展一个已有类型,使其能够适配一个或多个协议,语法格式如下
extension SomeType: SomeProtocol, AnotherProctocol {
// 协议实现写到这里
}
*/
// (1)计算型属性 : 扩展可以向已有类型添加计算型实例属性和计算型类型属性。
let addition = 3.add
print("加法运算后的值: \(addition)") // 输出: 加法运算后的值: 103
// (2)构造器 : 扩展可以向已有类型添加新的构造器。
// 这可以让你扩展其它类型,将你自己的定制类型作为构造器参数,或者提供该类型的原始实现中没有包含的额外初始化选项。
// 扩展可以向类中添加新的便利构造器 init(),但是它们不能向类中添加新的指定构造器或析构函数 deinit()
// (3)方法 : 扩展可以向已有类型添加新的实例方法和类型方法。
4.topics ({
print("扩展模块内")
})
1.topics({
print("内型转换模块内")
})
2.topics {
print("222222")
}
// (4)可变实例方法 : 通过扩展添加的实例方法也可以修改该实例本身。
// 结构体和枚举类型中修改self或其属性的方法必须将该实例方法标注为mutating,正如来自原始实现的修改方法一样
var trail1 = 2.3
trail1.square()
print("圆的面积: \(trail1)")
// (5)下标 : 扩展可以向一个已有类型添加新下标。
print(12[0]) // 输出 2
// (6)嵌套类型 : 扩展可以向已有的类、结构体和枚举添加新的嵌套类型:
//
// 协议规定了用来实现某一特定功能所必需的方法和属性。 任意能够满足协议要求的类型被称为遵循(conform)这个协议。
// 类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能
/** 语法 :
protocol SomeProtocol {
// 协议内容
}
*//**
要使类遵循某个协议,需要在类型名称后加上协议名称,中间以冒号:分隔,作为类型定义的一部分。遵循多个协议时,各协议之间用逗号,分隔。
struct SomeStructure: FirstPotocol, AontherProtocol {
// 结构体内容
}
如果类在遵循协议的同时拥有父类,应该将父类名放在协议名之前,以逗号分隔。
class SomeClass: SomeSuperClass, FirstPotocol, AontherProtocol {
// 类内容
}
*/
// (1)对属性的规定 : 协议用于指定特定的实例属性或类属性,而不用指定是存储型属性或计算型属性。此外还必须指明是只读的还是可读可写的
// 协议中的通常用var来声明变量属性,在类型声明后加上{ set get }来表示属性是可读可写的,只读属性则用{ get }来表示。
let studentH = classc()
studentH.stname = "swift"
studentH.marks = 98
studentH.marksseucred()
print(studentH.marks, studentH.result, studentH.present, studentH.subject, studentH.stname)
// (2)对 Mutating 方法的规定 : 有时需要在方法中改变它的实例。
// 例如,值类型(结构体,枚举)的实例方法中,将mutating关键字作为函数的前缀,写在func之前,表示可以在该方法中修改它所属的实例及其实例属性的值。
var res = days.wed
res.show()
// (3)对构造器的规定 : 协议可以要求它的遵循者实现指定的构造器。
// 你可以像书写普通的构造器那样,在协议的定义里写下构造器的声明,但不需要写花括号和构造器的实体,语法如下:
/** 语法
protocol SomeProtocol {
init(someParameter: Int)
}
*/
// (3)协议构造器规定在类中的实现 :
// 你可以在遵循该协议的类中实现构造器,并指定其为类的指定构造器或者便利构造器。在这两种情况下,你都必须给构造器实现标上"required"修饰符:
/** 语法 : required
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// 构造器实现
}
}
*/
// 使用required修饰符可以保证:所有的遵循该协议的子类,同样能为构造器规定提供一个显式的实现或继承实现。
// required,override : 如果一个子类重写了父类的指定构造器,并且该构造器遵循了某个协议的规定,那么该构造器的实现需要被同时标示required和override修饰符:
let af = mClass.init(aprot: 23)
let afshow = sClass.init(no1: 32, no2: 31)
print("af is : \(af.no1)", "afshow is \(afshow.no1)")
//(4)协议类型 : 尽管协议本身并不实现任何功能,但是协议可以被当做类型来使用
/** 协议可以像其他普通类型一样使用,使用场景:
作为函数、方法或构造器中的参数类型或返回值类型
作为常量、变量或属性的类型
作为数组、字典或其他容器中的元素类型
*/
var itemsss = [10,20,30].generate()
while let x = itemsss.next() {
print(x)
} // 输出 10 20 30
for lists in [1,2,3].map({i in i*5}) {
print(lists)
} // 输出 5 10 15
// (5)在扩展中添加协议成员
// 我们可以可以通过扩展来扩充已存在类型(类,结构体,枚举等)。 扩展可以为已存在的类型添加属性,方法,下标脚本,协议等成员。
// (6)协议的继承 : 协议能够继承一个或多个其他协议,可以在继承的协议基础上增加新的内容要求。
/** 协议的继承语法与类的继承相似,多个被继承的协议间用逗号分隔:
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
// 协议定义
}
*/
// (7)类专属协议 : class, 你可以在协议的继承列表中,通过添加class关键字,限制协议只能适配到类(class)类型。
/** 该class关键字必须是第一个出现在协议的继承列表中,其后,才是其他继承协议。格式如下:
protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
// 协议定义
}
*/
// (8)协议合成 : Swift 支持合成多个协议,这在我们需要同时遵循多个协议时非常有用。
/** 语法格式 :
protocol
*/
func showand(celebrator: Stname & Stage) {
print("\(celebrator.name) is \(celebrator.age) years old")
}
let snameaa = PerSonsss.init(name: "Priya", age: 20)
showand(snameaa) // 输出结果 Priya is 20 years old
// (9)检验协议的一致性 : 你可以使用is和as操作符来检查是否遵循某一协议或强制转化为某一类型。
/**
is操作符用来检查实例是否遵循了某个协议。
as?返回一个可选值,当实例遵循协议时,返回该协议类型;否则返回nil。
as用以强制向下转型,如果强转失败,会引起运行时错误。
*/
let objectsprotocol:[AnyObject] = [
Circle(radius: 2.0),
Country(area: 234),
Animal(legs: 23)]
for object in objectsprotocol {
if let objectAraea = object as? HasArea {
print("面积是:\(objectAraea.area)")
} else {
print("没有面积")
}
} // 输出结果 面积是:12.566 面积是:234.0 没有面积
//
// swift提供了泛型让你写出灵活且可重用的函数和类型, swift标准库是通过泛型代码构建出来的, swift的数组和字典都是泛型,
// 你可以创建一个Int数组,也可创建一个String数组,或者甚至于可以是任何其他 Swift 的类型数据数组。
// 以下实例是一个非泛型函数 exchange 用来交换两个 Int 值:
func exchange( a:inout Int, b:inout Int) {
let temp = a
a = b
b = temp
}
var numb1 = 20
var numb2 = 30
print("交换前数据: \(numb1) 和 \(numb2)")
exchange(&numb1, b: &numb2)
print("交换后数据: \(numb1) 和 \(numb2)")
// 泛型函数可以访问任何类型, 如 Int 或 String
// 以下实例是一个泛型函数 exchange 用来交换两个 Int 和 String 值:
func exchangefanxing
let temp = a
a = b
b = temp
}
var excnumb1 = 100
var excnumb2 = 200
print("交换前数据: \(excnumb1) 和 \(excnumb2)")
exchangefanxing(&excnumb1, b: &excnumb2)
print("交换后数据: \(excnumb1) 和 \(excnumb2)")
var excstr1 = "AAA"
var excstr2 = "BBB"
print("交换前数据: \(excstr1) 和 \(excstr2)")
exchangefanxing(&excstr1, b: &excstr2)
print("交换后数据: \(excstr1) 和 \(excstr2)")
/**
这个函数的泛型版本使用了占位类型名字(通常此情况下用字母T来表示)来代替实际类型名(如Int、String或Double)。
占位类型名没有提示T必须是什么类型,但是它提示了a和b必须是同一类型T,而不管T表示什么类型。
只有 exchange(_:_:)函数在每次调用时所传入的实际类型才能决定T所代表的类型。
另外一个不同之处在于这个泛型函数名后面跟着的占位类型名字(T)是用尖括号括起来的()。
这个尖括号告诉 Swift 那个T是 exchange(_:_:)函数所定义的一个类型。因为T是一个占位命名类型,Swift 不会去查找命名为T的实际类型。
*/
// (1)泛型类型 : Swift 允许你定义你自己的泛型类型。
// 自定义类、结构体和枚举作用于任何类型,如同Array和Dictionary的用法。
var tos = TOS<String>()
tos.push("swift")
print(tos.items)
tos.push("泛型")
print(tos.items)
let deleteos = tos.pop()
print(deleteos, "aaa")
// (2)扩展泛型类型 : extension, 你并不需要在扩展的定义中提供类型参数列表
// 原始类型定义中声明的类型参数列表在扩展里是可以使用的,并且这些来自原始类型中的参数名称会被用作原始定义中类型参数的引用。
if let first = tos.first {
print("栈顶部:\(first)")
}
// (3)类型约束 : 指定了一个必须继承自指定类的类型参宿,或者遵循一个特定的协议或协议构成
/** 类型约束语法 :
可以写一个在一个类型参数名后面的类型约束,通过冒号分割,来作为类型参数链的一部分。这种作用于泛型函数的类型约束的基础语法如下所示 :
func someFunction
// 这里是函数主体
}
*/
func findStringIndex(array: [String], _ valueToFind: String) -> Int? {
for (index, value) in array.enumerate() {
if value == valueToFind {
return index
}
}
return nil
}
let stringsss = ["cat", "dog", "llama", "parakeet", "terrapin"]
if let foundIndex = findStringIndex(stringsss, "llama") {
print("llama 的下标是 \(foundIndex)")
}
// (4)关联类型实例 : typealias 关键字用来设置关联类型
// 定义一个协议时,有的时候声明一个或多个关联类型作为协议定义的一部分是非常有用的。
var tos1 = TOSCon<String>()
tos1.push("swift1")
print(tos1.items)
tos1.push("泛型1")
print(tos1.items)
tos1.push("参数类型1")
print(tos1.items)
tos1.push("类型参数名1")
print(tos1.items)
// (5)Where 语句
/**
类型约束能够确保类型符合泛型函数或类的定义约束。
你可以在参数列表中通过where语句定义参数的约束。
你可以写一个where语句,紧跟在在类型参数列表后面,where语句后跟一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联类型间的等价(equality)关系。
// swift 3.0 之前版本写法
func allItemsMatch
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>(someContainer: C1, anotherContainer: C2) -> Bool {
*/
func allItemsMatch
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {
// 检查两个Container的元素个数是否相同
if someContainer.count != anotherContainer.count {
return false
}
// 检查两个Container相应位置的元素彼此是否相等
for i in 0..
if someContainer[i] != anotherContainer[i] {
return false
}
}
// 匹配所有项,返回 true
return true
}
var ttt = Stack<String>()
ttt.push("Swift2")
print(ttt.items)
ttt.push("泛型2")
print(ttt.items)
ttt.push("Where 语句2")
print(ttt.items)
var eos = ["Swift", "泛型", "Where 语句"]
print(eos)
//
/** swift 为代码中的实体提供了三种不同的访问级别:public、internal、private
访问级别 定义
Public 可以访问自己模块中源文件里的任何实体,别人也可以通过引入该模块来访问源文件里的所有实体。
Internal 可以访问自己模块中源文件里的任何实体,但是别人不能访问该模块中源文件里的实体。
Private 只能在当前源文件中使用的实体,称为私有实体。
*/// public为最高级访问级别,private为最低级访问级别
/** 语法 :
public class SomePublicClass ()
Internal calss SomeInternalClass ()
private class SomePrivareClass ()
public var somePlubilcVariable = 0
Internal let someInteralConstant = 0
private func somePrivateFunction() {}
*/// 除非有特殊的说明,否则实体都使用默认的访问级别internal。
// (1)函数类型访问权限 : 函数的访问级别需要根据该函数的参数类型和返回类型的访问级别得出。
/** 下面的例子定义了一个名为someFunction全局函数,并且没有明确地申明其访问级别
func someFunction() -> (SomeInternalClass, SomePrivareClass) {
// 函数实体
}
函数中其中一个类 SomeInternalClass 的访问级别是internal,另一个 SomePrivateClass 的访问级别是private。所以根据元组访问级别的原则,该元组的访问级别是private。
因为该函数返回类型的访问级别是private,所以你必须使用private修饰符,明确的声明该函数:
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// 函数实现
}
将该函数申明为public或internal,或者使用默认的访问级别internal都是错误的。
*/
// (2)枚举类型访问权限 : 枚举中成员的访问级别继承自该枚举,你不能为枚举中的成员单独申明不同的访问级别。
var stuAll = StudentAll.Name("swift")
var stualla = StudentAll.Mark(99,98,97)
switch stualla {
case .Name(let stuName):
print("学生:\(stuName)")
case .Mark(let math, let English, let Chines):
print("学生的成绩:\(math), \(English), \(Chines)")
}
// (3)子类访问权限 : 子类的访问级别不得高于父类的访问级别。比如说,父类的访问级别是internal,子类的访问级别就不能申明为public。
let sup = superClassss()
sup.show()
let sub = ssClassss()
sub.show
// (4)常量、变量、属性、下标访问权限 : 常量、变量、属性不能拥有比它们的类型更高的访问级别。下标也不能拥有比索引类型或返回类型更高的访问级别。
// private var privateInstance = SomePrivateClass()
// (5)Getter Setter 访问权限 : 常量、变量、属性、下标索引的Getters和Setters的访问级别继承自它们所属成员的访问级别
// Setter的访问级别可以低于对应的Getter的访问级别,这样就可以控制变量、属性或下标索引的读写权限。
let newCounter = samplegm()
newCounter.counter = 100
newCounter.counter = 800
// 输出结果: 计数器: 100 新增加数量 100 计数器: 800 新增加数量 700
// (6)构造器和默认构造器访问权限 :
/**
初始化: 我们可以给自定义的初始化方法申明访问级别,但是要不高于它所属类的访问级别。但必要构造器例外,它的访问级别必须和所属类的访问级别相同
如同函数或方法参数,初始化方法参数的访问级别也不能低于初始化方法的访问级别。
默认初始化方法: Swift为结构体、类都提供了一个默认的无参初始化方法,用于给它们的所有属性提供赋值操作,但不会给出具体值。
默认初始化方法的访问级别与所属类型的访问级别相同。
*/
let ababab = classAa()
let babab = clssAb() //输出结果: 10 30 10
// (7)协议访问权限: 如果想为一个协议明确的申明访问级别,那么需要注意一点,就是你要确保该协议只在你申明的访问级别作用域中使用。
// 如果你定义了一个public访问级别的协议,那么实现该协议提供的必要函数也会是public的访问级别。这一点不同于其他类型,比如,public访问级别的其他类型,他们成员的访问级别为internal。
// (8)扩展访问权限: 扩展成员应该具有和原始类成员一致的访问级别。比如你扩展了一个公共类型,那么你新加的成员应该具有和原始成员一样的默认的internal访问级别。
// 或者,你可以明确申明扩展的访问级别(比如使用private extension)给该扩展内所有成员申明一个新的默认访问级别。这个新的默认访问级别仍然可以被单独成员所申明的访问级别所覆盖
// (9)泛型访问权限: 泛型类型或泛型函数的访问级别取泛型类型、函数本身、泛型类型参数三者中的最低访问级别。
// (10) 类型别名: 任何你定义的类型别名都会被当作不同的类型,以便于进行访问控制。一个类型别名的访问级别不可高于原类型的访问级别。
// 注意:这条规则也适用于为满足协议一致性而给相关类型命名别名的情况。
//
//
// 闭包(Closures)是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。
// 全局函数和嵌套函数其实就是特殊的闭包。
/** 闭包形式有:
全局函数 嵌套函数 闭包表达式
有名字但不能捕获任何值。 有名字,也能捕获封闭函数内的值。 无名闭包,使用轻量级语法,可以根据上下文环境捕获值。
*/
/** Swift中的闭包有很多优化的地方:
根据上下文推断参数和返回值类型
从单行表达式闭包中隐式返回(也就是闭包体只有一行代码,可以省略return)
可以使用简化参数名,如$0, $1(从0开始,表示第i个参数...)
提供了尾随闭包语法(Trailing closure syntax)
语法:
{(parameters) -> return type in
statements
}
*/
let divde = {(val1: Int, val2: Int) -> Int in
return val1 / val2
}
let result1 = divde(200, 20)
print(result1) // 输出结果: 10
// (1)闭包表达式: 闭包表达式是一种利用简洁语法构建内联闭包的方式。
// sort 函数 :
let nameall = ["AT", "AE", "D", "S", "BE"]
func backwards(s1: String, s2: String) -> Bool { // 使用普通函数(或内嵌函数)提供排序功能,闭包函数类型需为(String, String) -> Bool。
return s1 > s2
}
var reversed = nameall.sort(backwards)
print(reserved) // 输出结果: ["S", "D", "BE", "AT", "AE"]
// (2)参数名称缩写: Swift 自动为内联函数提供了参数名称缩写功能,您可以直接通过$0,$1,$2来顺序调用闭包的参数。
var reversed1 = nameall.sort( { $0 > $1 } ) // $0和$1表示闭包中第一个和第二个String类型的参数。
print(reversed1) // 输出: ["S", "D", "BE", "AT", "AE"]
// (3)运算符函数: 实际上还有一种更简短的方式来撰写上面例子中的闭包表达式。
var reversed2 = nameall.sort(>) // Swift 的String类型定义了关于大于号 (>) 的字符串实现,其作为一个函数接受两个String类型的参数并返回Bool类型的值。 而这正好与sort(_:)方法的第二个参数需要的函数类型相符合。 因此,您可以简单地传递一个大于号,Swift可以自动推断出您想使用大于号的字符串函数实现:
print(reversed2) // 输出: ["S", "D", "BE", "AT", "AE"]
// (4)尾随闭包: 尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用
/**
func someFunctionThatTakesAClosure(closure: () -> Void) {
// 函数体部分
}
// 以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure({
// 闭包主体部分
})
// 以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure() {
// 闭包主体部分
}
// 注意: 如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把()省略掉。var reversed3 = nameall.sort { $0 > $1}
*/
var reversed3 = nameall.sort() { $0 > $1}
print(reversed3) // 输出: ["S", "D", "BE", "AT", "AE"]
// (5)捕获值:
// (6)闭包是引用类型:
//
// Optional Chaining, 是一种可以请求和调用属性、方法和子脚本的过程,用于请求或调用的目标可能为nil。
/** 可选链返回两个值:
如果目标有值,调用就会成功,返回该值
如果目标为nil,调用将返回nil
*/// 多次请求或调用可以被链接成一个链,如果任意一个节点为nil将导致整条链失效
// (1)可选链可替代强制解析 : ? !
// (2)为可选链定义模型类: 你可以使用可选链来多层调用属性,方法,和下标脚本。这让你可以利用它们之间的复杂模型来获取更底层的属性,并检查是否可以成功获取此类底层属性
// (3)通过可选链调用方法: 你可以使用可选链的来调用可选值的方法并检查方法调用是否成功。即使这个方法没有返回值,你依然可以使用可选链来达成这一目的。
// (4)使用可选链调用下标脚本:
// (5)通过可选链接调用来访问下标:
// (6)访问可选类型的下标: 如果下标返回可空类型值,比如Swift中Dictionary的key下标。可以在下标的闭合括号后面放一个问号来链接下标的可空返回值:
// (7)连接多层链接:
// (8)对返回可选值的函数进行链接: 我们还可以通过可选链接来调用返回可空值的方法,并且可以继续对可选值进行链接。
}
override func didReceiveMemoryWarning() { // 重写父类方法
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/************* 实例方法 **************/
func aAddB(a:Int, b:Int) -> Int { //(实例方法)
return a+b
}
var countA = 0
func countADD(addCount:Int) { //(实例方法)
countA += addCount
}
}
//-----------------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------------//
class ViewController2: UIViewController {
private var daysdays = ["Sun", "Mun", "Tue", "Wed", "Thu", "Fri", "Sat"]
subscript(index:Int) -> String {
get {
return daysdays[index] // 声明下标脚本语言
}
set(newValue) {
self.daysdays[index] = newValue // 执行赋值操作
}
}
}
//-----------------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------------//
class StudentDetails { // (1)基类, 没有继承其它类的类,称之为基类(Base Class)。
var English = 99 // 默认值,
var Math: Int {
return English - 5
}
func recordMarks() {
print("父类中的方法>>>>>>")
}
}
class Tom: StudentDetails { // (2)子类, 子类指的是在一个已有类的基础上创建一个新的类
var Chines = 10
override var English: Int {
didSet {
Chines = English / 2
}
}
override var Math: Int { // get-only
return super.Math - 5
}
override func recordMarks() {
super.recordMarks()
print("子类中的重写>>>>>>>")
}
}
//-----------------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------------//
// (1)构造过程
class ShoppingListItem { // 以下实例中,ShoppingListItem类中的所有属性都有默认值,且它是没有父类的基类,它将自动获得一个可以为所有属性设置默认值的默认构造器
var name : String?
var quantity = 1
var purchased = false
}
// (2)指定构造器实例
class Mooncake {
var huamei: String // 局部存储变量
init(huaMei: String) {
self.huamei = huaMei // 初始化
}
}
class Ronglang: Mooncake {
var ronglang : String // 新的子类存储变量
init(huaMei: String, rongLang: String) { // 初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化
self.ronglang = rongLang // 初始化
super.init(huaMei: huaMei) // 初始化超类
}
}
// (3)便利构造器实例
class carCalss {
var aodi: String // 局部存储变量
init(aoDI: String) {
self.aodi = aoDI // 初始化
}
}
class AODIClass: carCalss {
var dazhong: String
init(aoDI: String, daZhong: String) {
self.dazhong = daZhong
super.init(aoDI: aoDI)
}
// 便利方法只需要一个参数
override convenience init(aoDI: String) {
self.init(aoDI: aoDI, daZhong: "")
}
}
// (4)构造器的继承和重载
class WineClass {
var redWine = "红酒"
var desccription: String {
return "\(redWine) 不错!"
}
}
class REDWineClass: WineClass {
override init() { // 重载构造器
super.init()
redWine = "红酒名酒。。。"
}
}
// (5)指定构造器和便利构造器 继承实例
class GameClass {
var mobileGames: String
init(mobilegame: String) {
self.mobileGames = mobilegame
}
convenience init() {
self.init(mobilegame: "逐鹿天下手游")
}
}
class MobileGameClass: GameClass {
var zhuluGame : String
init(moblegame: String, zhulu: String) {
self.zhuluGame = zhulu
super.init(mobilegame: moblegame)
}
override convenience init(mobilegame: String) {
self.init(moblegame: mobilegame, zhulu: "逐鹿")
}
}
// (6) 可失败构造器
class planet {
var name : String
init(name: String) {
self.name = name;
}
convenience init () {
self.init(name: "[No Planets]")
}
}
class planets: planet {
var count : Int
init(name: String, count: Int) {
self.count = count
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, count: 1)
}
}
// (7)可失败构造器 init!
struct StuRecord {
let stname : String
init!(stname: String) {
if stname.isEmpty {
return nil
}
self.stname = stname
}
}
// (8)析构过程
var counter = 0; // 引用计数器
class BaseClass {
init() {
counter += 1;
}
deinit {
counter -= 1;
}
}
// (9)循环强引用
class SignClass {
let name : String
init(name : String) {
self.name = name
}
var baseSs : SSClass?
deinit {
print(" #\(name) 被析构") // 循环强引用, 不会被调用
}
}
class SSClass {
let number : Int
init(number: Int) {
self.number = number
}
var baseSign : SignClass?
deinit {
print("SSClass #\(number) 被析构") // 循环强引用, 不会被调用
}
}
// (10)弱引用实例
class Module {
let name : String
init(name: String) {
self.name = name
}
var sub : SubModul?
deinit {
print(" \(name) 主模块 被析构") // 弱引用, 会被调用
}
}
class SubModul {
let number : Int
init(number : Int) {
self.number = number
}
weak var topic : Module?
deinit {
print("子模块 topic 数为 \(number)") // 弱引用, 会被调用
}
}
// (10)无主引用实例
class StudentPeter {
let name : String
var section : MarkPeter?
init(name: String) {
self.name = name
}
deinit {
print("析构函数:学生姓名: \(name)") // 无主引用, 会被调用
}
}
class MarkPeter {
let marks : Int
unowned let stname: StudentPeter
init(marks: Int, stname: StudentPeter) {
self.marks = marks
self.stname = stname
}
deinit {
print("析构函数:学生的分数: \(marks)") // 无主引用, 会被调用
}
}
// (11)闭包引起的循环强引用 实例
class HTMLElement {
let name : String
let text : String?
lazy var asHTML: () -> String = { // 闭包在其闭包体内使用了self(引用了self.name和self.text)
if let text = self.text { // 因此闭包捕获了self,这意味着闭包又反过来持有了HTMLElement实例的强引用
return "<\(self.name)>\(text)<\(self.name)>"
} else {
return "<\(self.name)>"
}
}
lazy var asasHTML: () -> String = {
[unowned self] in // 无主引用是正确的解决循环强引用的方法
if let text = self.text {
return "<\(self.name)>\(text)\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String?) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitalized")
}
}
// (12)扩展
extension Int { //a.下面的例子向 Int 类型添加了 4个计算型实例属性并扩展其功能
var add: Int {
return self + 100
}
var sub: Int {
return self - 10
}
var mul: Int {
return self * 10
}
var div: Int {
return self / 5
}
}
struct sum {
var num1 = 100, num2 = 200
}
struct diff {
var no1 = 200, no2 = 100
}
struct mult {
var a = sum()
var b = diff()
}
extension mult { // 构造器扩展
init(x: sum, y:diff) {
_ = x.num1 + x.num2
_ = y.no1 + y.no2
}
}
extension Int { // 下面的例子向Int类型添加一个名为 topics 的新实例方法
func topics(summation: () -> ()) {
for _ in 0..<self {
summation()
}
}
}
// 下面的例子向 Swift 的 Double 类型添加了一个新的名为 square 的修改方法,来实现一个原始值的平方计算: mutating
extension Double {
mutating func square() {
let PI = 3.1415
self = PI * self * self
}
}
// 以下例子向 Swift 内建类型Int添加了一个整型下标。该下标[n]返回十进制数字 subscript
extension Int {
subscript(var muttable: Int) -> Int {
var no1 = 1
while muttable > 0 {
no1 += 10
muttable -= 1
}
return (self / no1) % 10
}
}
// (13)协议
protocol classa {
var marks : Int { set get }
var result : Bool { get }
func attendance() -> String
func marksseucred() -> String
}
protocol calssb: classa {
var present : Bool { get set }
var subject : String { get set }
var stname : String { get set }
}
class classc: calssb {
var marks = 96
let result = true
var present = false
var subject = "Swift 协议"
var stname = "Protocol"
func attendance() -> String {
return "The \(stname) has secured 99% attendance"
}
func marksseucred() -> String {
return "\(stname) has scored \(marks)"
}
}
// 对 Mutating 方法的规定
protocol daysofaweek {
mutating func show()
}
enum days: daysofaweek {
case sun, mon, tue, wed, thurs, fri, sat
mutating func show() {
switch self {
case sun:
self = sun
print("Sunday")
case mon:
self = mon
print("Monday")
default:
print("no such day !")
}
}
}
//对构造器的规定
protocol tcpprotocol {
init(aprot: Int)
}
class tcpClass: tcpprotocol { // required, 你可以在遵循该协议的类中实现构造器,并指定其为类的指定构造器或者便利构造器
required init(aprot: Int) {
}
}
class mClass {
var no1 : Int // 局部变量
init(aprot: Int) {
self.no1 = aprot // 初始化
}
}
class sClass: mClass, tcpprotocol {
var no2 : Int
init(no1: Int, no2: Int) {
self.no2 = no2
super.init(aprot: no1)
}
// 因为遵循协议,需要加上"required"; 因为继承自父类,需要加上"override"
required override convenience init(aprot: Int) {
self.init(no1:aprot, no2:0)
}
}
// 协议类型
protocol Generator {
associatedtype memebers
func next() -> memebers?
}
// 在扩展中添加协议成员
protocol AgeClassficationProtocol {
var age: Int { get }
func agetype() -> String
}
class Personss {
let firstname : String
let lastname : String
var age : Int
init(firstname: String, lastname: String) {
self.firstname = firstname
self.lastname = lastname
self.age = 10
}
}
extension Personss: AgeClassficationProtocol {
func fullname() -> String {
var c : String
c = firstname + " " + lastname
return c
}
func agetype() -> String {
switch age {
case 0...2:
return "Baby"
case 2...12:
return "Child"
case 13...19:
return "Teenager"
case let x where x > 65:
return "Elderly"
default:
return "Normal"
}
}
}
// 协议的继承
protocol sAgeClassProtocol: AgeClassficationProtocol {
}
// 类专属协议
protocol specalClassProtocol: class, AgeClassficationProtocol {
}
// 协议合成
protocol Stname {
var name : String { get }
}
protocol Stage {
var age : Int { get }
}
struct PerSonsss:Stname, Stage {
var name: String
var age: Int
}
// 检验协议的一致性 : is as? as
protocol HasArea {
var area: Double { get }
}
class Circle: HasArea { // 定义了Circle类,都遵循了HasArea协议
let PI = 3.1415
let radius : Double
var area: Double { return PI * radius * radius }
init(radius: Double) {
self.radius = radius
}
}
class Country: HasArea { // 定义了Country类,都遵循了HasArea协议
var area: Double
init(area: Double) {
self.area = area
}
}
class Animal { // Animal是一个没有实现HasArea协议的类
var legs : Int
init(legs: Int) {
self.legs = legs
}
}
// (14)泛型
struct TOS
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
extension TOS { // 扩展泛型类型
var first : T? {
return items.isEmpty ? nil : items[items.count - 1]
}
}
// 关联类型实例
protocol Container {
// 定义了一个ItemType关联类型
associatedtype ItemType
mutating func append(item: ItemType)
var count : Int { get }
subscript(i: Int) -> ItemType { get }
}
struct TOSCon
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
mutating func append(item: T) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> T {
return items[i]
}
}
// 下面的例子定义了一个名为allItemsMatch的泛型函数,用来检查两个Container实例是否包含相同顺序的相同元素。
// 如果所有的元素能够匹配,那么返回一个为true的Boolean值,反之则为false。
struct Stack
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() ->T {
return items.removeLast()
}
mutating func append(item: T) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> T {
return items[i]
}
}
// 访问权限 :
// 枚举类型访问权限 :
public enum StudentAll { //枚举 StudentAll 被明确的申明为 public 级别,那么它的成员 Name,Mark 的访问级别同样也是 public:
case Name(String)
case Mark(Int, Int, Int)
}
// 子类访问权限: 子类访问级别不得高于父类访问级别
public class superClassss {
private func show() {
print("父类")
}
}
// 访问级别不能低于超类 internal > public
internal class ssClassss: superClassss {
override internal func show() {
print("子类")
}
}
// Getter Setter 访问权限
class samplegm {
private var counter: Int = 0 {
willSet(newTotal) {
print("计数器: \(newTotal)")
}
didSet {
if counter > oldValue {
print("新增加数量: \(counter - oldValue)")
}
}
}
}
// 构造器和默认构造器访问权限
class classAa {
required init() {
var a = 10
print(a)
}
}
class clssAb: classAa {
required init() {
var b = 30
print(b)
}
}