Swift
常量和变量
-
var
定义变量,设置之后可以修改 -
let
定义常量,设置之后不可以修改 - 语句末尾不用使用
;
- 在 Swift 中使用
print()
替代 OC 中的NSLog
,print
的性能更好 - 用
let
定义常量,该常量的内存地址不允许修改,但是可以修改其内部的属性
- 常量&变量的使用原则:初学的时候,尽量先用
let
,只有需要变的时候,再用var
,能够更加安全
- 初次接触
Swift
中会因为简单的var
let
误以为Swift
中的类型非常松,其实所有变量的准确类型都是在赋值的同时自动推导的 -
Swift
是对类型要求非常严格的一门语言,一个值永远不会被自动转换成其他类型,如果要转换,必须显示转换
//常量不可以改变
let number = 10;
//变量
var number1 = 10;
number1 = 20;
//Swift可以自行做类型推断
print(number)
//定义变量(如果指定类型,一定要显性的)
var name:String = "shkljsjd"
var age:Int = 12;
var height:Float = 180.5
var 体重:Double = 12.2
var gender:Bool = true
var sex: Character = "m"
var telephone = "123456789"
//类型转换
let 整型体重 = Int(height)
print(整型体重)
var 整型电话 = Int(telephone)!
print(整型电话)
字符串
使用String
的原因
-
String
是一个结构体,性能更高-
String
目前具有了绝大多数 NSString 的功能 -
String
支持直接遍历
-
-
NSString
是一个OC
对象,性能略差 -
Swift
提供了String
和NSString
之间的无缝转换
- 在Swift中绝大多数的情况下,推荐使用 String 类型
//遍历字符串
let str = "qwerasdf"
for s in str {
print(s)
}
//获取字符串的长度
print(str2.characters.count)
// 字符串快速拼接
let str1 = "zhangsan"
let str2 = "lisi"
let i = 10
print(str1 + str2)//可以理解成数组
print("\(str1) \(str2) \(i)")//这里可以使用\(变量名)的方式快速拼接字符串
//字符串的拼接
//这里是swift中的字符串(非常非常费劲)的拼接方法
let str: String = "zhangwu"
var subStr = str.substringWithRange(Range(start: str.startIndex, end: str.endIndex))
str.insert("1", atIndex: str2.startIndex.advancedBy(3))
//所以一把建议把swift里面的字符串转换成NSString进行拼接(删除方法同理)
let str3: NSString = "zhangsanwangwu"
print(str3.substringWithRange(NSMakeRange(0, 3)))
// 格式化字符串(这里提供了一种和OC中的stringWithFormat一样的方法,需要注意的后面的arguments是一个数组,即使一个变量也要放入数组中)
for _ in 0...10 {
let str = String(format: "zhangsan - %04d", arguments: [arc4random_uniform(100)])
print(str)
}
数组,字典,元组
数组
- 如果定义数组时指定了保存对象的类型,择不能向数组中添加其他类型的内容
-
let
定义的数组是不可变的
-
var
定义的数组是可变的
// 数组中保存的都是字符串
let arr = ["zhangsan", "lisi"]
// 数组中保存的是 NSObject
let arr1 = ["zhangsan", 1]
// 添加元素
array.append("lisi")
//更新
array[0] = "zhangwu"
// 删除元素
array.removeAtIndex(1)
// 拼接数组
var array2 = [String]()
array2.append("1")
array2.append("2")
array += array2
字典
// 定义并实例化字典(这种类型是开发中常用的类型)
var dict = [String: AnyObject]()
//添加(更新)
dict["name"] = "zhangsan"
dict["age"] = 18
// 删除
dict.removeValueForKey("age")
// 合并字典
var dict2 = ["name": "wangwu", "age": 80, "title": "boss"]
for (k, v) in dict2 {
dict.updateValue(v, forKey: k)
}
元组
//元组(tuple)(可以放任意类型)
//不定义标记
let student = ("1",1,1.1,[1],[1:1])
//访问元组元素
print(student.4)
//定义标记
let student1 = (姓名:"小明",性别:"W",年龄:[19,12,20])
//访问元组元素
print(student1.年龄[1])
print(student1.2[1])
- 总结 :
- 数组[index,value]:里面放着两种属性,一种是索引,一种是元素,数组中放着的只有元素,我们可以通过索引找到元素
- 字典[key,value]:和oc中一样都放着键值对,可以通过key访问value
- 元祖[标记,value]:可以看做是数组和字典的结合体,里面的标记可以不定义(默认像数组中的index),可以定义(就像字典中的key,但是字典中的key是有类型的,标记是无类型的)
循环,遍历,switch,枚举
循环和遍历
//whlie
while false
{
}
//类似于do...while
repeat
{
}while false
// 循环
for var i = 0; i < 10; i++ {
print(i)
}
// 遍历 0 ~ 9(省略号之间不能有空格)
for i in 0..<10 {
print(i)
}
// 遍历 0 ~ 10(省略号之间不能有空格)
for i in 0...10 {
print(i)
}
// 特殊写法(如果不关心循环本身的索引,可以用通配符'_'忽略)
for _ in 0...10 {
print("hello")
}
//数组的遍历
var studentArr = [1,2,3,4,5,6,7,8,9]
for item in studentArr
{
print("item = \(item)")
}
//可以遍历数组中的所以和元素(间接用到了元组的特性)
for(index,value)in studentArr.enumerate()
{
print("index =\(index) value = \(value)")
}
//字典的遍历(同样间接用到了元组的特性)
var studentDic = ["姓名":"张三","爱好":"男"�"]
for (key,value)in studentDic
{
print("key = \(key) value = \(value)")
}
switch和枚举
//swtich(自带break,可以重复,但是找到一个就不会找第二个)
var name1 = "小明"
switch name1
{
case "小明":print(name1)
//要想要自带贯穿效果(重复之后也继续寻找)加fallthrough关键字
fallthrough
case "小明":print(name1)
//一定要包含所有条件
default: print("不存在")
}
//case可以写区间
var age1 = 12
switch age1 {
case 10...15:
print("a")
default:
print("默认")
}
//当age2 == 15成立的时候把age2赋给age
var age2 = 15
switch age2{
case let age where age2 == 15:
print("age = \(age)")
default: break
}
//遍历元祖
var studentTuple = (姓名:"张三",性别:"男",年龄:12)
switch studentTuple
{
case ("张三","男",12):
print("找对了")
case (_,_,12):
print("找对了")//只要一个条件成立就可以进
default:
break
}
//枚举(和oc一样默认初始值是0,如果修改初始值的话需要制指定类型,swift的枚举创建必须要带case)
enum season :Int
{
case spring = 2
case summer
case autumn
case winter
}
print(season.autumn)
//打印枚举值的值
print(season.autumn.rawValue)
var today = season.summer
//筛选枚举
switch today
{
case.spring:print("春天")
case.summer:print("夏天")
case.autumn:print("秋天")
case.winter:print("冬天")
}
//枚举也可以这样定义(case后面跟着多个元素,枚举值的类型也可以是String类型)
enum City:String
{
case 北京 = "北京",上海
case 石家庄,武汉
case 青岛
}
函数
//函数
//无参无返回
func func1()
{
print("无参无返回值")
}
//无参有返回
func func2()->String
{
print("无参有返回值")
return "小明"
}
//有参无返回
func func3 (a :String)
{
print("有参无返回值")
}
//有参有返回
func func4 (a:Int)->String
{
print("有参有返回值")
return String(a)
}
//函数调用
func1()
func2()
func3("123")
func4(1)
//不定参数(这点与oc中的不大一样,如果传入的参数不固定可以这样写)
func add(a:Int...)->Int
{
var result = 0
for item in a
{
result += item
}
return result
}
//调用的时候传入的参数就是不固定的
print(add(1,2,3,4))
//返回值是多个参数
func func5()->(Int,String)
{
return(1,String(123))
}
//交换
var m = 1
var n = 2
//变成指针(inout)(只有改变指针才能达到换值的目的)
//xy是外部参数,ab是内部参数,系统默认第一个不会帮我们省略,以后的参数会帮我们省略,所以要将x写出来,但是y可以省略
func change(inout x a:Int,inout y b:Int)
{
let temp = a
a = b
b = temp
}
change(x: &m, y: &n)
结构体和类
- Swift要求类和结构体中的存储属性(非lazy)在对象初始化完毕后必须有值
结构体
- Swift里面的结构体和oc中的不太一样,苹果官方更推荐在开发中使用结构体,Swift中的结构体更像类,可以定义属性和方法
- Swift中的结构体是值类型,也就是说在赋值的时候是拷贝一块内存空间,类似于oc中的深拷贝
- Swift中的结构体不可以继承
struct Father
{
init ()
{
print("______")
}
}
//结构体
struct Person{
//存储属性(和@property一样)
var name:String!
var age:NSInteger!
//计算属性(不会存值,依赖于其他存储属性,没有存储空间)
var fatherAge:NSInteger
{
set {
age = newValue - 20
}
get {
return age + 20
}
}
//初始化方法
init()
{
print("初始化方法")
}
//自定义初始化方法
init(name:String,age:NSInteger)
{
self.name = name
self.age = age
}
//懒加载属性(用到时在加载)
lazy var father:Father = Father()
//类属性
static var Arr = Array()
//对象方法
func eat(){
print("吃饭")
}
//类方法
static func happy() {
print("类方法happy")
}
}
类
- 类可以继承
- 类是引用类型,赋值的过程是复制的指针,两个对象同时指向同一块内存空间,修改一个影响另一个,类似于浅拷贝
class Person1:NSObject
{
//重写父类的方法必须用关键字override
override init()
{
print("初始化人")
}
}
class dog: NSObject
{
//存储属性
var name:NSString!
var age:NSInteger!
//计算属性
var fatherAge:NSInteger{
set{
age = newValue / 10
}
get {
return age * 10
}
}
//懒加载属性
lazy var person:Person1 = Person1()
//类属性
static var arr = Array()
//类方法 (class和static都可以创建类方法,唯一的区别是用static修饰的类,其子类不可以重写该类的方法)
static func eat()
{
print("吃")
}
//对象方法
func happy()
{
print("happy")
}
//自定义初始化方法
init(name:String,age :NSInteger)
{
self.name = name
self.age = age
}
}
protocol和extension
- 在swift中协议和oc的区别不是很大,而extension更像是oc中的category,extension不但可以给类扩展,也可以给协议扩展
protocol
- swift中的协议把可选协议个必须实现的协议分开
//必须实现的协议
protocol PersonDelegate
{
//对象方法
func numberOfDog()->String
// 类方法
static func numberOfDog()
//属性
var gender:String{get set}
//类属性
static var classRoom:String{ get set}
}
//可选协议
@objc protocol DogDelegate{
optional var name:String{set get }
//方法
optional func eat()->String
}
extension
- 正因为swift中的extension有这个特性,所以开发过程中我们可以充分利用extension的特性可以把我们的项目模块化(例如创建tableView的时候,两个代理可以用extension写出来)
//扩展
extension Person {
func text (){
print("asda")
}
}
//创建一个类
class Student:NSObject
{
var delegate:DogDelegate?
override init() {
super.init()
self.delegate = self
}
// func eat() -> String {
// return "123"
// }
}
extension Student : DogDelegate
{
func eat() -> String {
return "123"
}
}
闭包
- swift中的闭包类似于oc中的block
- 闭包表达式的类型和函数的类型一样(也就是in之前的部分)
- in关键字的目的是便于区分返回值和执行语句
- 关于闭包表达式的优化
- 1.类型优化, 由于函数中已经声明了闭包参数的类型, 所以传入的实参可以不用写类型
- 2.返回值优化, 同理由于函数中已经声明了闭包的返回值类型,所以传入的实参可以不用写类型
- 3.参数优化, swift可以使用$索引的方式来访问闭包的参数, 默认从0开始
//闭包
var block :(Int->Void)?
//实现
block = {(a:Int) in
return a
}
block!(0)
//第二种写法(可以省略,$0第一个参数,$1代表第二个参数)
var bb:(Int,String)->String
bb = {
return $1
}
bb(1,"2")
//闭包作为函数回调
func eat(block:(a:Int)->(Int))->Int
{
return block(a: 1)
}
eat { (a) -> (Int) in
return a
}