标签:
学习swift第一步打印Hello World
print("Hello World")
swift是不用加分号的
什么是常量?
常量是在程序运行过程中不能改变值的量
什么时变量?
变量是可以在程序运行过程中不断变化的量
在swift当中常量和变量必须在使用前声明
用let来声明常量,用var来声明变量
常量定义方式:
可以用任何你喜欢的字符作为常量和变量名,包括Unicode字符
常量与变量名不能包含以下:
数学符号,箭头,保留的(或者非法的)Unicode码位,连线与制表符。
也不能以数字开头,但是可以在常量与变量名的其他地方包含数字。
注意:Swift中的常量必须在定义时初始化(OC可以不初始化),否则会报错
letmax=10
let??=100
变量定义方式:
在OC当中先定义再初始化————>(以下为OC写法)
intage;
age =10;
也可以定义的同时初始化
intage =10;
在swift当中先定义再初始化:
varage 这种写法会直接报错.
报错原因:(type annotation missing in pattern:没有指定数据类型)
在Swift中如果想要先定义一个变量,
以后使用时再初始化必须在定义时告诉编译器变量的类型(类型标注)
写法为:
varage:Int
age = 20
定义的同时初始化:
在Swift中如果定义的同时初始化一个变量,可以不用写数据类型
编译期会根据初始化的值自动推断出变量的类型(类型推断机制)
varage:Int=20
varage =20
基本数据类型
OC:
整型int intValue = 10;
浮点型double doubleValue = 10.10; float floatValue = 5.1;
长long
短short
有符号signed
无符号unsigned
各种类型的数据的取值范围在不同位的编译器下取值范围不同
Swift:注意关键字大写
整型
varintValue:Int=10
浮点型
varintValue1:Double=10.10表示64位浮点数
varintValue2:Float=9.9表示32位浮点数
如果按照长度划分,Swift中的长短比OC更加精确
varintValue3:Int8=6
varintValue4:Int16=7
varintValue5:Int32=8
varintValue6:Int64=9
有符号无符号,默认是有符号的(UInt8/UInt16/UInt32/UInt64)
varuintValue7:UInt=10
注意:无符号的数比有符号的取值范围更大,因为符号位也用来存值
Swift是类型安全的语言,如果取值错误会直接报错,而OC不会
取值不对
OC:unsignedintintValue = -10;不会报错
Swift:varintValue:UInt= -10会报错
溢出:
OC:intintValue =INT_MAX+1;不会报错
Swift:varintValue:UInt=UInt.max +1会报错
数据类型的相互赋值(隐式类型转换)
OC可以隐式类型转换
intintValue =10;
doubledoubleValue = intValue;
Swift:不具有隐式类型转换
在Swift中“值永远不会被隐式转换为其他类型”(OC中可以隐式类型转换)
以下语句会报错
varintValue:Int=10
vardoubleValue:Double= intValue
数据类型转换
Swift不允许隐式类型转换,但可以使用显示类型转换(强制类型转换)
OC写法
intintValue =10;
doubledoubleValue = (double)intValue;
Swift写法:
varintValue:Int=10
vardoubleValue:Double
doubleValue=Double(intValue)
注意:Double()并不会修改intValue的值
而是通过intValue的值生成一个临时的值赋值给doubleValue
print(intValue)
print(doubleValue)
算术运算符:
+ - * / % ++ --
除了取模,其它和OC一样,包括优先级
varresult =10+10
result =10*10
result =10-10
result =10/10
print(result)
注意:Swift是安全严格的编程语言,会在编译时候检查是否溢出
但是只会检查字面量而不会检查变量
所以在Swift中一定要注意隐式溢出
遇到这种问题可以利用溢出运算符解决该问题:
http://www.yiibai.com/swift/overflow_operators.html
取模%
OC:只能对整数取模
NSLog(@"%tu",10%3);
Swift:支持小数取模
print(10%3.5)
自增自减
varnumber =10
number++
print(number)
number--
print(number)
赋值运算
varnum1 =10
num1 =20
num1 +=10
num1 -=10
num1 /=10
num1 *=10
num1 %=5
print(num1)
基本用法和OC一样,唯一要注意的是表达式的值
OC:表达式的结合方向是从左至右
整个表达式的值整体的值等于最后一个变量的值,简而言之就是连续赋值
写法为:
intnum1;
intnum2;
num2 = num1 =10;
NSLog(@"%d",num2);
Swift:不允许连续赋值, Swift中的整个表达式是没有值的.
主要是为了避免if (c == 9)
这种情况误写为if (c = 9) ,c = 9是一个表达式,表达式是没有值的
所以在Swift中if (c = 9)不成立
下面这个写法是在swift当中不允许的
varnum1:Int
varnum2:Int
num2 = num1 =10
关系运算符
> < >= <= == != ?:
关系运算符,得出的值是Bool值,基本用法和OC一样
varresult1:Bool=250>100
varresult2 =250>100?250:100
print(result2)
逻辑运算符
C语言和OC并没有真正的Bool类型
C语言的Bool类型非0即真
OC语言的Bool类型是typedef signed char BOOL;
Swift引入了真正的Bool类型
Bool true false
Swift中if的条件只能是一个Bool的值或者是返回值是Bool类型的表达式
OC中if可以是任何整数(非0即真),
但是存在的问题是可能将判断写错,写成了赋值if(isOpen = 2)
在开发中为了避免这个问题
有经验的程序员会这样写if(2 == isOpen)来避免这个问题.
在Swift中很好的解决了这个问题
逻辑运算符在swift当中只能操作Bool类型数据
在OC当中是非0即真.可以操作整形
在swift当中不允许这种操作.其它基本和OC一致
varopen =false
if!open
{
print("打开")
}
varage =20
varheight =180
varwage =30000
if(age >25&& age <40&& height >175) || wage >20000
{
print("恒仔")
}
区间
闭区间:包含区间内所有值a...b例如: 1...5
半闭区间:包含头不包含尾a..
注意: 1.Swift刚出来时的写法是a..b
2.区间只能用于整数,写小数会有问题
foriin1...5
{
print(i)
}
foriin1..<5
{
print(i)
}
什么是元组
在其它语言中很早就是有元组这个概念,但是对于OC程序员来说这是一个新的概念
官方定义:元组(tuples)把多个值组合成一个复合值。
元组内的值可以是任意类型,并不要求是相同类型。
将多个相同或者不同类型的值用一个小括号括起来就是一个元组
定义元组
letstudent = ("lzh",30,99.8)
print(student)
print(student.0)
print(student.1)
print(student.2)
元组其实和结构体很像,只是不需要提前定义类型.
元组其实是复合类型,小括号中可以写任意类型
也可以指定数据类型
如果指定了数据类型,那么对应的必须是其它定的数据类型,否则会报错.
letstudent: (String,Int,Double) = ("lzh",30,99.8)
定义元组其它方式
指明元组元素的名称
letstudent = (name:"lzh",age:30,score:99.8)
print(student.name)
print(student.age)
print(student.score)
通过指定的名称提取元组对应的值,会将对应位置的值赋值给对应位置的名称
let(name , age , score) = ("lzh",30,99.8)
print(name)
print(age)
print(score)
如果不关心元组中的某个值可以利用_通配符来忽略提取
letstudent = ("lzh",10,20)
let(name , age ,_) = student
print(name)
print(age)
在以前没有元组之前C和OC语言是通过传入指针或者返回结构体的方式来返回多个值的
而有了元组之后就可以实现让一个函数返回多个值
使用可选类型(optionals)来处理值可能缺失的情况。
C 和 Objective-C 中并没有可选类型这个概念。
最接近的是 Objective-C 中的一个特性,
一个方法要不返回一个对象要不返回nil,nil表示“缺少一个合法的对象”
可选值: optionals有两种状态:
1.有值
2.没有值,没有值就是nil
?表示两种状态,一种是有值(有具体的某个值)
一种是没有值(没有代表为nil)
当为?修饰时,表明这个变量有可能为nil
有值
varoptValue:Int? =9
没有值
varoptValue:Int?
varoptValue:Int? =nil
可选值可以利用if语句来进行判断
varoptValue:Int? =10
ifoptValue !=nil
{
print("有值:\(optValue)")
}else
{
print("没有值:\(optValue)")
}
输出结果:有值:Optional(10)
varoptValue:Int?
ifoptValue !=nil
{
print("有值:\(optValue)")
}else
{
print("没有值:\(optValue)")
}
输出结果:没有值:nil
varoptValue:Int?=nil
ifoptValue !=nil
{
print("有值:\(optValue)")
}else
{
print("没有值:\(optValue)")
}
输出结果:没有值:nil
提取可选类型的值(使用!强制解析)
将optValue中的整型值强制拿出来赋值给变量result,
换句话说就是告诉编译器optValue一定有值
因为可选类型有两种状态有值和没有值,所以需要告诉编译器到底有没有值
需要注意的是如果强制解析optValue
但是optValue中没有值时会引发一个运行时错误
varoptValue:Int? =9
varresult:Int=optValue!
print(result)
输出结果:9
varoptValue6:Int?
varresult2:Int=optValue6!
print(result2)
结果为报错:
fatal error:
unexpectedly found nil while unwrapping an Optional value
可选绑定
为了更安全的解析可选类型的值,一般情况下使用可选绑定
如果optValue没有值就不会做任何操作
如果optValue有值会返回true并将optValue的值赋值给result执行大括号中的内容
varoptValue:Int? =9
ifletresult =optValue
{
print(result)
}
字符
OC当中的字符:charcharValue =‘a‘;
swift当中的字符:varcharValue1:Character="a"
Swift和OC字符不一样
1.Swift是用双引号
2.Swift中的字符类型和OC中的也不一样
OC中的字符占一个字节,因为它只包含ASCII表中的字符
而Swift中的字符除了可以存储ASCII表中的字符还可以存储unicode字符.
OC的字符是遵守ASCII标准的,Swift的字符是遵守unicode标准的
所以可以存放时间上所有国家语言的字符(大部分)
OC当中:charcharValue =‘李’;错误
swift当中:varcharValue2:Character="李"正确
注意:双引号中只能放一个字符,如下是错误写法
varcharValue3:Character="ab"
字符串
C:
char*stringValue ="ab";
charstringArr ="ab";
OC:
NSString*stringValue ="ab";
Swift:
varstringValue1 ="ab"
C语言中的字符串是以\0结尾的,例如:
char*stringValue ="abc\0bcd";
printf("%s", stringValue);
输出结果:abc
OC语言中的字符串也是以\0结尾的,例如:
NSString*stringValue =@"abc\0bcd";
NSLog(@"%@", stringValue);
swift当中的字符串和C语言/OC语言中的字符串是不一样的
varstringValue ="abc\0bcd"
print(stringValue)
输入结果:abcbcd
字符串常用方法
计算字符串长度:
C:
char*stringValue ="abc李";
printf("%tu",strlen(stringValue));
输出结果:6
OC:
NSString*stringValue =@"abc李";
NSLog(@"%tu", stringValue.length);
输出结果:4以UTF16计算
swift:
varstringValue ="abc李"
print(stringValue.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))
输出结果:6和C语言一样计算字节数
字符串拼接
C:
charstr1[] ="abc";
char*str2 ="bcd";
char*str =strcat(str1, str2);
printf("%s",str);
输出结果:abcbcd
OC:
NSMutableString*str1 = [NSMutableStringstringWithString:@"abc"];
NSString*str2 =@"bcd";
[str1appendString:str2];
NSLog(@"%@", str1);
输出结果:abcbcd
swift:
varstr1 ="g";
varstr2 ="gxq";
varstr =str1+str2;
print(str)
输出结果:ggxq
格式化字符串
OC:
NSString*str =
[NSMutableString
stringWithFormat:@"http://ios.564697292@qq.cn/pic/%tu.png",index];
NSLog(@"%@", str);
输入结果:http://ios.564697292@qq.cn/pic/10.png
swift:
varindex =10
varstr ="http://www.564697292@qq.com/pic/\(index).png"
print(str)
输入结果:http://www.564697292@qq.com/pic/10.png
字符串比较:
oc:
NSString*str1 =@"abc";
NSString*str2 =@"abc";
if([str1compare:str2] ==NSOrderedSame)
{
NSLog(@"相等");
}else
{
NSLog(@"不相等");
}
输出结果:相等
NSString*str1 =@"abc";
NSString*str2 =@"abc";
if([str1isEqualToString:str2])
{
NSLog(@"相等");
}else
{
NSLog(@"不相等");
}
输出结果:相等
Swift:(== / != / >= / <=),和C语言的strcmp一样是逐个比较
varstr1 ="abc";
varstr2 ="abc";
ifstr1 == str2
{
print("相等");
}else
{
print("不相等");
}
输出结果:相等
varstr1 ="abd";
varstr2 ="abc";
ifstr1 >= str2
{
print("大于等于");
}else
{
print("不大于等于");
}
输出结果:大于等于
判断前后缀
OC:
NSString*str =@"http://564697292@qq.com";
if([strhasPrefix:@"http"]) {
NSLog(@"是url");
}
if([strhasSuffix:@".cn"]) {
NSLog(@"是顶级域名");
}
输出结果:是url
是顶级域名
Swift:
varstr ="http://www.564697292@qq.com"
ifstr.hasPrefix("http") {
print("是url");
}
ifstr.hasSuffix(".com") {
print("是顶级域名");
}
输出结果:是url
是顶级域名
大小写转换
OC:
NSString*str =@"abc.txt";
NSLog(@"%@", [struppercaseString]);
NSLog(@"%@", [strlowercaseString]);
输出结果:ABC.TXT
abc.txt
Swift:
varstr ="abc.txt";
print(str.uppercaseString)
print(str.lowercaseString)
输出结果:ABC.TXT
abc.txt
转换为基本数据类型
OC:
NSString*str =@"250";
NSIntegernumber = [strintegerValue];
NSLog(@"%tu", number);
输出结果:250
如果str不能转换为整数,那么可选类型返回nil
str = "250sb"不能转换所以可能为nil
varstr ="250"
varnumber:Int? =Int(str)
ifnumber !=nil
{
以前的版本println会自动拆包,现在的不会
print(number!)
}
数组定义:
OC:
有值数组
NSArray*arr0 =@[@1,@2,@3];
NSArray*arr1 = [NSArrayarrayWithObjects:@1,@2,@3,nil];
NSLog(@"%@", arr1);
输出结果:
2016-01-06 01:04:49.180 test[11687:2096671] (
1,
2,
3
)
空数组
NSArray*arr =@[];
NSArray*arr1 = [NSArrayarray];
NSLog(@"%@", arr1);
输出结果:
2016-01-06 01:06:04.132 test[11703:2106199] (
)
不可变数组:NSArray
可变数组:NSMutableArray
swift:
有值数组
vararr0 = [1,2,3]
vararr1:Array= [1,2,3]
vararr2:Array = [1,2,3]
vararr3: [Int] = [1,2,3]
print(arr3)
输出结果:[1, 2, 3]
空数组
vararr5 = []
vararr6 = [Int]()
vararr7 =Array()
print(arr7)
输出结果:[]
可变数组:
vararr8 = []
不可变数组:
letarr9 = []
元素类型
OC:
NSArray*arr =@[@1,@"gxq",@130];
NSLog(@"%@", arr);
输出结果:
2016-01-06 01:13:07.987 test[11891:2163044] (
1,
gxq,
130
)
swift:
vararr = [1,"gxq",130]
print(arr)
输出结果:[1, gxq, 130]
如果想明确表示数组中存放的是不同类型的数据
可以使用Any关键字,表示数组中可以存放不同类型的数据
vararr:Array = [1,"gxq",130]
print(arr)
输出结果:[1, gxq, 130]
指定数组当中只能存放Int型,如果存放其它类型会直接报错
vararr:Array = [1,10,130]
print(arr)
输出结果:[1, 10, 130]
获取长度
OC:
NSArray*arr =@[@1,@2,@3];
NSLog(@"%tu", arr.count);
输出结果:2016-01-06 01:19:54.874 test[12086:2209180] 3
swift:
vararr = [1,2,3]
print(arr.count)
输出结果:3
判断是否为空
OC:
NSArray*arr =@[];
NSLog(@"result = %d", arr.count!=0);
输出结果:2016-01-06 01:25:14.252 OCTest[12249:2255010] result = 0
swift:
vararr = [1,2,3]
print(arr.isEmpty)
输出结果:false
检索
OC:
NSArray*arr =@[@1,@2,@3];
NSLog(@"%@", arr[0]);
输出结果:2016-01-06 01:26:46.816 OCTest[12275:2269853] 1
swift:
vararr = [1,2,3]
print(arr[0])
输出结果:1
追加
OC:
NSMutableArray*arr =
[NSMutableArrayarrayWithObjects:@1,@2,@3,nil];
[arraddObject:@4];
NSLog(@"%@", arr);
输出结果:
2016-01-06 01:28:47.111 OCTest[12297:2286198] (
1,
2,
3,
4
)
swift:
vararr = [1,2,3]
arr.append(4);
print(arr)
输出结果:[1, 2, 3, 4]
vararr = [1,2,3]
arr+= [4]
print(arr)
输出结果:[1, 2, 3, 4]
vararr = [1,2,3]
arr+= [4]
arr+= [5,6,7]
输出结果:[1, 2, 3, 4, 5, 6, 7]
vararr = [1,2,3]
arr+= [4]
arr+= [5,6,7]
arr+=arr[0...3]
print(arr)
输出结果:[1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4]
插入
OC:
NSMutableArray*arr =
[NSMutableArrayarrayWithObjects:@1,@2,@3,nil];
[arrinsertObject:@4atIndex:0];
NSLog(@"%@", arr);
输出结果:
2016-01-06 01:36:10.450 OCTest[12374:2339079] (
4,
1,
2,
3
)
swift:
vararr = [1,2,3]
arr.insert(4, atIndex:0);
print(arr)
输出结果:[4, 1, 2, 3]
更新
OC:
NSMutableArray*arr =
[NSMutableArrayarrayWithObjects:@1,@2,@3,nil];
arr[0] =@8;
NSLog(@"%@", arr);
输出结果:
2016-01-06 01:37:28.482 OCTest[12397:2350177] (
8,
2,
3
)
swift:
vararr = [1,2,3]
arr[0] =8
print(arr)
输出结果:[8, 2, 3]
删除
OC:
NSMutableArray*arr1 =
[NSMutableArrayarrayWithObjects:@1,@2,@3,nil];
[arr1removeObject:@1];
NSLog(@"%@", arr1);
NSMutableArray*arr2 =
[NSMutableArrayarrayWithObjects:@1,@2,@3,nil];
[arr2removeLastObject];
NSLog(@"%@", arr2);
NSMutableArray*arr3 =
[NSMutableArrayarrayWithObjects:@1,@2,@3,nil];
[arr3removeAllObjects];
NSLog(@"%@", arr3);
输出结果:
2016-01-06 01:39:49.831 OCTest[12418:2370779] (
2,
3
)
2016-01-06 01:39:49.832 OCTest[12418:2370779] (
1,
2
)
2016-01-06 01:39:49.832 OCTest[12418:2370779] (
)
swift:
vararr1 = [1,2,3]
arr1.removeAtIndex(0)
print(arr1)
vararr2 = [1,2,3]
arr2.removeLast()
print(arr2)
vararr3 = [1,2,3]
是否保持容量,如果为true,即便删除了容量依然存在,容量是2的倍数
arr3.removeAll(keepCapacity:false)
print(arr3)
print(arr3.capacity)
输出结果:
[2, 3]
[1, 2]
[]
0
Range
OC:
NSMutableArray*arr =
[NSMutableArrayarrayWithObjects:@1,@2,@3,nil];
[arrremoveObjectsInRange:NSMakeRange(0,2)];
NSLog(@"%@", arr);
输出结果:
2016-01-06 01:43:17.863 OCTest[12441:2396986] (
3
)
swift:
vararr = [1,2,3]
arr.removeRange(Range(start:1, end:2))
print(arr)
输出结果:[1, 3]
vararr = [1,2,3]
arr.removeRange(0...0)
print(arr)
输出结果:[2, 3]
varrange =0...5
print(range)
输出结果:0..<6
OC:
NSMutableArray*arr =
[NSMutableArrayarrayWithObjects:@1,@2,@3,nil];
NSRangerange =NSMakeRange(0,2);
[arrreplaceObjectsInRange:range
withObjectsFromArray:@[@99,@88,@77,@66]];
NSLog(@"%@", arr);
输出结果:
2016-01-06 14:56:45.493 OCTest[3599:667081] (
99,
88,
77,
66,
3
)
swift:
vararr = [1,2,3]
arr.replaceRange(1..<2, with: [99,88,77,66])
print(arr)
输出结果:[1, 99, 88, 77, 66, 3]
vararr = [1,2,3]
arr.replaceRange(Range(start:0, end:2), with: [99,88,77,66])
print(arr)
输出结果:[99, 88, 77, 66, 3]
遍历
OC:
NSArray*arr =@[@1,@2,@3];
for(inti =0; i < arr.count; i++) {
NSLog(@"%@", arr[i]);
}
输出结果:
2016-01-06 15:00:10.702 OCTest[3635:694273] 1
2016-01-06 15:00:10.703 OCTest[3635:694273] 2
2016-01-06 15:00:10.703 OCTest[3635:694273] 3
NSArray*arr =@[@1,@2,@3];
for(NSNumber*numberinarr) {
NSLog(@"%@", number);
}
输出结果:
2016-01-06 15:03:43.192 OCTest[3684:723081] 1
2016-01-06 15:03:43.193 OCTest[3684:723081] 2
2016-01-06 15:03:43.194 OCTest[3684:723081] 3
swift:
vararr1 = [1,2,3]
forvari =0; i
{
print(arr1[i])
}
fornumberinarr1
{
print(number)
}
输出结果:
1
2
3
vararr2 = [1,2,3]
fornumberinarr2[0..<3]
{
print(number)
}
输出结果:
1
2
3
定义字典
OC:
NSDictionary*dict =[NSDictionarydictionaryWithObject:
@"gxq"forKey:@"name"];
NSLog(@"%@", dict);
输出结果:
2016-01-06 15:09:11.214 OCTest[3773:761032] {
name = gxq;
}
NSDictionary*dict =[NSDictionarydictionaryWithObjectsAndKeys:
@"name",@"gxq",
@"age",@20,nil];
NSLog(@"%@", dict);
输出结果:
2016-01-06 15:13:39.853 OCTest[3831:792730] {
gxq = name;
20 = age;
}
NSDictionary*dict =@{@"name":@"gxq",@"age":@20};
NSLog(@"%@", dict);
输出结果:
2016-01-06 15:14:57.616 OCTest[3841:801710] {
age = 20;
name = gxq;
}
swift:
key一定要是可以hash的(String, Int, Float, Double, Bool)
value没有要求
vardict = ["name":"gxq","age":20]
print(dict)
vardict1:Dictionary= ["name":"gxq","age":20]
print(dict1)
vardict2:Dictionary = ["name":"gxq","age":20]
print(dict2)
vardict3:[String:AnyObject] = ["name":"gxq","age":20]
print(dict3)
vardict4:[String:AnyObject] =
Dictionary(dictionaryLiteral: ("name","gxq"), ("age",20))
print(dict4)
输出结果:
["age": 20, "name": gxq]
["age": 20, "name": gxq]
["age": 20, "name": gxq]
["age": 20, "name": gxq]
["age": 20, "name": gxq]
可变字典:
vardict5 = [:]
不可变字典:
letdict6 = [:]
字典操作
OC:
获取
NSDictionary*dict =@{@"name":@"gxq",@"age":@20};
NSLog(@"%@", dict[@"name"]);
输出结果:
2016-01-06 15:26:00.351 OCTest[3923:881138] gxq
修改
NSMutableDictionary*dict =
[NSMutableDictionarydictionaryWithObjectsAndKeys:
@"name",@"gxq",
@"age",@20,nil];
dict[@"name"] =@"iversion";
NSLog(@"%@", dict[@"name"]);
NSMutableDictionary*dict =
[NSMutableDictionarydictionaryWithObjectsAndKeys:
@"name",@"gxq",
@"age",@20,nil];
[dictsetObject:@"iversion"forKey:@"name"];
NSLog(@"%@", dict[@"name"]);
输出结果:
2016-01-06 15:27:01.704 OCTest[3933:890317] iversion
2016-01-06 15:28:21.398 OCTest[3943:899613] iversion
swift:
获取
vardict = ["name":"gxq","age":20]
print(dict["name"]!)
输出结果:gxq
修改
vardict = ["name":"gxq","age":20]
dict["name"] ="iverson"
print(dict["name"]!)
vardict1 = ["name":"gxq","age":20]
dict1.updateValue("iverson", forKey:"name")
print(dict["name"]!)
输出结果:
iverson
iverson
更新
updateValue返回一个可选类型
如果字典中不存在需要更新的key,那么返回nil,如果存在返回原始值
vardict = ["name":"gxq","age":25]
ifletorignal =dict.updateValue("iverson", forKey:"name")
{
print(dict["name"]!)
print(orignal)
}
输出结果:
iverson
gxq
updateValue返回一个可选类型
如果字典中不存在需要更新的key,那么返回nil并且会将新的键值对添加到字典中
vardict = ["name":"gxq","age":25]
ifletorignal =dict.updateValue("iverson", forKey:"abc")
{
print(dict["abc"]!)
print(orignal)
}
print(dict)
输出结果:["abc": iverson, "age": 25, "name": gxq]
添加
OC:
NSMutableDictionary*dict =
[NSMutableDictionarydictionaryWithObjectsAndKeys:
@"name",@"gxq",
@"age",@25,nil];
dict[@"height"] =@100;
NSLog(@"%@", dict);
输出结果:
2016-01-06 15:35:11.734 OCTest[4025:946250] {
gxq = name;
25 = age;
height = 100;
}
NSMutableDictionary*dict =
[NSMutableDictionarydictionaryWithObjectsAndKeys:
@"name",@"GXQ",
@"age",@30,nil];
[dictsetObject:@200forKey:@"height"];
NSLog(@"%@", dict);
输出结果:
2016-01-06 15:36:15.768 OCTest[4035:953931] {
GXQ = name;
30 = age;
height = 200;
}
swift:
vardict = ["name":"Gxq","age":50]
dict["height"] =160;
print(dict)
输出结果:["height": 160, "age": 50, "name": Gxq]
删除
OC:
NSMutableDictionary*dict =
[NSMutableDictionarydictionaryWithObjectsAndKeys:
@"lzh",@"name",
@30,@"age",nil];
[dictremoveObjectForKey:@"name"];
NSLog(@"%@", dict);
输出结果:
2016-01-06 15:40:37.801 OCTest[4058:981747] {
age = 30;
}
NSMutableDictionary*dict =
[NSMutableDictionarydictionaryWithObjectsAndKeys:
@"lzh",@"name",
@30,@"age",nil];
[dictremoveAllObjects];
NSLog(@"%@", dict);
输出结果:
2016-01-06 15:41:20.705 OCTest[4068:989096] {
}
swift:
vardict = ["name":"gxq","age":10]
dict.removeValueForKey("name")
print(dict)
输出结果:["age": 10]
removeValueForKey返回一个可选类型
如果字典中不存在需要删除的key,那么返回nil并且不会执行任何操作
如果存在则删除key对应的值,并且返回被删除的值
vardict = ["name":"gxq","age”:20]
ifletorignal =dict.removeValueForKey("names")
{
print(dict)
print(orignal)
}
print(dict)
输出结果:["age": 30, "name": gxq]
vardict = ["name”:"gxq","age":30]
dict.removeAll(keepCapacity:true)
遍历字典
OC:
NSMutableDictionary*dict =
[NSMutableDictionarydictionaryWithObjectsAndKeys:
@"gxq",@"name",
@40,@"age",nil];[dictenumerateKeysAndObjectsUsingBlock:^(idkey,idobj,BOOL*stop) {
NSLog(@"key = %@ value = %@", key, obj);
}];
输出结果:
2016-01-06 15:45:59.810 OCTest[4117:1022823] key = name value = gxq
2016-01-06 15:45:59.811 OCTest[4117:1022823] key = age value = 40
NSMutableDictionary*dict =
[NSMutableDictionarydictionaryWithObjectsAndKeys:
@"gxq",@"name",
@40,@"age",nil];
NSArray*keys = [dictallKeys];
for(NSString*keyinkeys) {
NSLog(@"%@", key);
}
输出结果:
2016-01-06 15:48:07.861 OCTest[4137:1039198] name
2016-01-06 15:48:07.862 OCTest[4137:1039198] age
NSMutableDictionary*dict =
[NSMutableDictionarydictionaryWithObjectsAndKeys:
@"gxq",@"name",
@40,@"age",nil];
NSArray*keys = [dictallValues];
for(NSString*keyinkeys) {
NSLog(@"%@", key);
}
输出结果:
2016-01-06 15:49:20.375 OCTest[4148:1049548] gxq
2016-01-06 15:49:20.376 OCTest[4148:1049548] 40
vardict1 = ["name":"Gxq","age":30]
for(key , value)indict1
{
print("key =\(key) value =\(value)")
}
输出结果:
key = age value = 30
key = name value = Gxq
vardict2 = ["name":"Gxq","age":40]
forkeyindict2.keys
{
print("key =\(key)")
}
输出结果:
key = age
key = name
vardict3 = ["name":"Gxq","age":50]
forvalueindict3.values
{
print("value =\(value)")
}
输出结果:
value = 50
value = Gxq
if语句基本使用
OC:
intage1 =10;
intage2 =20;
intmax;
max = age2;
if(age1 > age2) {
max = age1;
}
NSLog(@"%d", max);
输出结果:20
if(age1 > age2) {
max = age1;
}else
{
max = age2;
}
NSLog(@"%d", max);
输出结果:20
如果只有一条指令if后面的大括号可以省略
Swift:
if条件表达式{指令} if条件表达式{指令} else{指令}
0.if后的圆括号可以省略
1.只能以bool作为条件语句
2.如果只有条指令if后面的大括号不可以省略
varage1:Int=10
varage2:Int=20
varmax:Int
max=age2;
ifage1>age2
{
max=age1
}
print(max)
输出结果:20
ifage1>age2
{
max=age1;
}else
{
max=age2;
}
print(max)
输出结果:20
多分支
floatscore =99.9;
if(score >=90) {
NSLog(@"优秀");
}else
{
if(score >=60) {
NSLog(@"良好");
}else
{
NSLog(@"不给力");
}
}
输出结果:2016-01-06 16:08:05.833 OCTest[4239:1177565]优秀
if(score >=90) {
NSLog(@"优秀");
}elseif(score >=60)
{
NSLog(@"良好");
}else
{
NSLog(@"不给力");
}
输出结果:2016-01-06 16:08:05.834 OCTest[4239:1177565]优秀
swift:
varscore =99.9;
ifscore>=90
{
print("优秀")
}elseifscore>=60
{
print("良好")
}else
{
print("不给力")
}
输出结果:优秀
while循环
OC:
格式:while(循环保持条件){需要执行的语句}
inti =0;
intsum =0;
while(i <=10) {
sum = i++;
}
NSLog(@"%d",sum);
输出结果:10
inti =0;
intsum =0;
while(i <=10)
sum = i++;
NSLog(@"%d", sum);
输出结果:10
如果只有一条指令while后面的大括号可以省略
Swift:
0.while后的圆括号可以省略
1.只能以bool作为条件语句
2.如果只有条指令while后面的大括号不可以省略
vari:Int=0
varsum:Int=0
while(i<=10)
{
sum=i++
}
print("\(sum)")
输出结果:10
vari1:Int=0
varsum1:Int=0
whilei1<=10
{
sum1=i1++
}
print("\(sum1)")
输出结果:10
do while循环
inti =0;
intsum =0;
do{
sum = i++;
}while(i <=10);
NSLog(@"%d", sum);
输出结果:10
inti =0;
intsum =0;
do
sum = i++;
while(i <=10);
NSLog(@"%d", sum);
输出结果:10
如果只有一条指令while后面的大括号可以省略
swift:
Swift2.0之后变为repeat while, do用于捕捉异常
0.while后的圆括号可以省略
1.只能以bool作为条件语句
2.如果只有条指令do后面的大括号不可以省略
vari2:Int=0
varsum2:Int=0
repeat{
sum2=i2++;
}while(i2<=10)
print(sum2)
输出结果:10
vari3:Int=0
varsum3:Int=0
repeat{
sum3=i3++;
}whilei3<=10
print(sum3)
输出结果:10
OC:
intsum =0;
for(inti =0; i <=10; i++) {
sum = i++;
}
NSLog(@"%d", sum);
输出结果:10
intsum =0;
inti =0;
for(; i <=10; i++) {
sum = i++;
}
NSLog(@"%d", sum);
输出结果:10
intsum =0;
inti =0;
for(; i <=10; ) {
sum = i++;
i++;
}
NSLog(@"%d", sum);
输出结果:10
intsum =0;
inti =0;
for( ; ; ) {
sum = i++;
i++;
if(i >10) {
break;
}
}
NSLog(@"%d", sum);
输出结果:10
intsum =0;
inti =0;
for( ; ; ) {
sum = i++;
i++;
NSLog(@"%d", sum);
}
输出结果:死循环
如果只有一条指令for后面的大括号可以省略
for后面的三个参数都可以省略,如果省略循环保持语句,那么默认为真
Swift:
0.for后的圆括号可以省略
1.只能以bool作为条件语句
2.如果只有条指令for后面的大括号不可以省略
3.for后面的三个参数都可以省略,如果省略循环保持语句,那么默认为真
varsum:Int=0
forvari =0; i <=10; i++
{
sum= i++
}
print(sum)
输出结果:10
varsum1:Int=0
vari1 =0
for;i1<=10;i1++
{
sum1=i1++
}
print(sum1)
输出结果:10
varsum2:Int=0
vari2 =0
for;i2<=10;
{
sum2=i2++
i2++
}
print(sum2)
输出结果:10
varsum3:Int=0
vari3 =0
for; ;
{
sum3=i3++
i3++
ifi3>10
{
break
}
}
print(sum3)
输出结果:10
for in循环
OC:
格式: for (接收参数in取出的参数) {需要执行的语句}
for in含义:从(in)取出什么给什么,直到取完为止
for(NSNumber*iin@[@1,@2,@3,@4,@5]) {
NSLog(@"%@", i);
}
输出结果:
2016-01-06 17:17:38.669 OCTest[4599:1510680] 1
2016-01-06 17:17:38.670 OCTest[4599:1510680] 2
2016-01-06 17:17:38.670 OCTest[4599:1510680] 3
2016-01-06 17:17:38.670 OCTest[4599:1510680] 4
2016-01-06 17:17:38.670 OCTest[4599:1510680] 5
NSDictionary*dict =@{@"name":@"LZH",@"age":@100};
for(NSArray*keysindict.allKeys) {
NSLog(@"%@", keys);
}
输出结果:
2016-01-06 17:18:17.419 OCTest[4609:1515258] name
2016-01-06 17:18:17.420 OCTest[4609:1515258] age
NSDictionary*dict =@{@"name":@"lzh",@"age":@30};
for(NSArray*keysindict.allValues) {
NSLog(@"%@", keys);
}
输出结果:
2016-01-06 17:18:47.592 OCTest[4619:1519194] lzh
2016-01-06 17:18:47.593 OCTest[4619:1519194] 30
Swift:
for in一般用于遍历区间或者集合
varsum4:Int=0
fori4in1...10会将区间的值依次赋值给i
{
sum4+= i4;
}
print(sum4)
输出结果:55
fordictin["name":"LZH","age":30]
{
print(dict);
}
输出结果:
("age", 30)
("name", lzh)
for(key, value)in["name":"LZH","age":30]
{
print("\(key) =\(value)")
}
输出结果:
age = 30
name = LZH
break:跳出循环,无论循环保持条件是否还为真都不会再执行循环
continue:跳出本次循环,如果循环保持条件还为真还会继续执行循环
OC:
NSArray*arr =@[@1,@3,@5,@7,@8];
for(NSNumber*numinarr) {
if([numisEqualTo:@(7)]) {
NSLog(@"找到幸运数字");
break;
}
NSLog(@"没有找到幸运数字");
}
输出结果:
2016-01-06 17:23:07.807 OCTest[4684:1554896]没有找到幸运数字
2016-01-06 17:23:07.808 OCTest[4684:1554896]没有找到幸运数字
2016-01-06 17:23:07.808 OCTest[4684:1554896]没有找到幸运数字
2016-01-06 17:23:07.808 OCTest[4684:1554896]找到幸运数字
NSArray *arr =@[@1,@3,@5,@7,@8];
intcount =0;
for(NSNumber *numinarr) {
if(num.intValue %2!=0) {
NSLog(@"不能被2整除");
continue;
}
NSLog(@"能被2整除");
count++;
}
NSLog(@"count = %d", count);
输出结果:
2016-01-06 17:23:48.005 OCTest[4694:1560348]不能被2整除
2016-01-06 17:23:48.006 OCTest[4694:1560348]不能被2整除
2016-01-06 17:23:48.006 OCTest[4694:1560348]不能被2整除
2016-01-06 17:23:48.006 OCTest[4694:1560348]不能被2整除
2016-01-06 17:23:48.006 OCTest[4694:1560348]能被2整除
2016-01-06 17:23:48.006 OCTest[4694:1560348] count = 1
Swift:
vararr:Array = [1,3,5,7,8]
fornuminarr{
ifnum ==7
{
print("找到幸运数字")
break
}
print("没有找到幸运数字")
}
输出结果:
没有找到幸运数字
没有找到幸运数字
没有找到幸运数字
找到幸运数字
vararr1:Array = [1,3,5,7,8]
varcount:Int=0
fornuminarr1{
ifnum %2!=0
{
print("不能被2整除")
continue
}
print("能被2整除")
count++
}
print("count =\(count)")
输出结果:
不能被2整除
不能被2整除
不能被2整除
不能被2整除
能被2整除
count = 1
格式: switch(需要匹配的值) case匹配的值:需要执行的语句break;
可以穿透
可以不写default
default位置可以随便放
在case中定义变量需要加大括号,否则作用域混乱
不能判断对象类型
OC:
charrank =‘A‘;
switch(rank) {
case‘A‘:
NSLog(@"优");
break;
case‘B‘:
NSLog(@"良");
break;
case‘C‘:
NSLog(@"差");
break;
default:
NSLog(@"没有评级");
break;
}
输出结果:优
可以穿透
charrank =‘A‘;
switch(rank) {
case‘A‘:
NSLog(@"优");
case‘B‘:
NSLog(@"良");
break;
case‘C‘:
NSLog(@"差");
break;
default:
NSLog(@"没有评级");
break;
}
输出结果:
2016-01-06 20:15:41.643 OCTest[6617:1852944]优
2016-01-06 20:15:41.644 OCTest[6617:1852944]良
可以不写default
charrank =‘A‘;
switch(rank) {
case‘A‘:
NSLog(@"优");
break;
case‘B‘:
NSLog(@"良");
break;
case‘C‘:
NSLog(@"差");
break;
}
输出结果:
2016-01-06 20:16:30.171 OCTest[6629:1860297]优
default位置可以随便放
charrank =‘E‘;
switch(rank) {
default:
NSLog(@"没有评级");
break;
case‘A‘:
{
intscore =100;
NSLog(@"优");
break;
}
case‘B‘:
NSLog(@"良");
break;
case‘C‘:
NSLog(@"差");
break;
}
输出结果:
2016-01-06 20:17:14.444 OCTest[6639:1866501]没有评级
在case中定义变量需要加大括号,否则作用域混乱
charrank =‘A‘;
switch(rank) {
case‘A‘:
{
intscore =100;
NSLog(@"优");
break;
}
case‘B‘:
NSLog(@"良");
break;
case‘C‘:
NSLog(@"差");
break;
}
输出结果:
2016-01-06 20:17:56.849 OCTest[6649:1872272]优
不能判断对象类型
以下写法是错误的
NSNumber*num =@100;
switch(num) {
case@100:
NSLog(@"优");
break;
default:
NSLog(@"没有评级");
break;
}
Swift:
Swift:可以判断对象类型, OC必须是整数
不可以穿透
可以不写break
不能不写default
default位置只能在最后
在case中定义变量不用加大括号
varrank ="A"
switchrank{
case"A":相当于if
print("优")
case"B":相当于else if
print("优")
case"C":相当于else if
print("优")
default:相当于else
print("没有评级")
}
因为不能穿透所以不能这么写
以下写法是错误的:
varrank1 ="A"
switchrank1{
case"A":
case"B":
print("优")
case"C":
print("优")
default:
print("没有评级")
}
只能这么写
varrank1 ="A"
switchrank1{
case"A","B":注意OC不能这样写
print("优")
case"C":
print("差")
default:
print("没有评级")
}
不能不写default
以下写法是错误的:
varrank2 ="A"
switchrank2{
case"A":
print("优")
case"B":
print("良")
case"C":
print("差")
}
default位置只能在最后
以下写法是错误的:
varrank3 ="A"
switchrank3{
default:
print("没有评级")
case"A":
print("优")
case"B":
print("良")
case"C":
print("差")
}
在case中定义变量不用加大括号
varrank4 ="A"
switchrank4{
case"A":
varnum =10
print("优")
case"B":
print("良")
case"C":
print("差")
default:
print("没有评级")
}
输出结果:优
区间和元祖匹配
varnum =10;
switchnum{
case1...9:
print("个位数")
case10...99:
print("十位数")
default:
print("其它数")
}
输出结果:十位数
varpoint = (10,15)
switchpoint{
case(0,0):
print("坐标在原点")
case(1...10,10...20):可以在元祖中再加上区间
print("坐标的X和Y在1~10之间")
case(_,0):X可以是任意数
print("坐标的X在X轴上")
default:
print("Other")
}
输出结果:坐标的X和Y在1~10之间
值绑定
varpoint = (1,10)
switchpoint{
case(varx,10):会将point中X的值赋值给X
print("x=\(x)")
case(varx,vary):会将point中XY的值赋值给XY
print("x=\(x) y=\(y)")
casevar( x, y):
print("x=\(x) y=\(y)")
default:
print("Other")
}
输出结果:
x= 1
根据条件绑定
varpoint = (100,10)
switchpoint{
只有where后面的条件表达式为真才赋值并执行case后的语句
casevar(x, y)wherex > y:
print("x=\(x) y=\(y)")
default:
print("Other")
}
输出结果:x= 100 y= 10
函数:
完成某个特定任务的代码块,给代码起一个合适的名称称之为函数名称.
以后需要执行代码块只需要利用函数名称调用即可.
好比每个人都有一个名字,叫名字就能找到对应的人
OC:
不带参数
- (void)say
{
NSLog(@"hello");
}
带有一个参数
- (void)sayWithName:(NSString *)name
{
NSLog(@"hello %@", name);
}
带有多个参数
- (void)sayWithName:(NSString *)name age:(NSInteger)age
{
NSLog(@"hello %@ , I‘m %tu years old", name, age);
}
有返回值
- (NSString *)info
{
return@"name = gxq, age = 30";
}
有返回值,并且带有返回值
- (NSString *)infoWithName:(NSString *)name age:(NSInteger)age
{
return[NSString stringWithFormat:
@"name = %@,
age = %tu", name, age];
}
swift:
格式:
func函数名称(参数名:参数类型,参数名:参数类型...) ->函数返回值{函数实现部分}
无参无返回值
funcsay() ->Void
{
print("hello")
}
say()
输出结果:hello
funcsay1()如果没有返回值可以不写
{
print("hello")
}
say1()
输出结果:hello
有参无返回值
funcsayWithName(name:String)
{
print("hello\(name)")
}
sayWithName("gxq")
输出结果:hello gxq
带有多个参数
funcsayWithName(name:String, age:Int)
{
print("hello\(name) , I‘m\(age) years old ")
}
sayWithName("gxq", age:30)
输出结果:hello gxq , I‘m 30 years old
无参有返回值
funcinfo() ->String
{
return"name = gaowei, age = 30"
}
print(info())
输出结果:name = gaowei, age = 30
有参有返回值
funcinfo(name:String, age:Int) ->String
{
return"name =\(name), age =\(age)"
}
print(info("lzh", age:30))
输出结果:name = lzh, age = 30
嵌套函数
vararr:Array = ["lzh","gaowei","520"]
funcshowArray(array:[String])
{
fornumberinarray
{
print("\(number), ")
}
}
showArray(arr)
输出结果:
lzh,
gaowei,
520,
funcbubbleSort(inoutarray:[Int])
{
funcswap(inouta:Int,inoutb:Int)
{
lettemp = a
a = b
b = temp
}
letcount = array.count;
forvari =1; i < count; i++
{
forvarj =0; j < (count - i); j++
{
ifarray[j] > array[j +1]
{
swap(&array[j], b: &array[j +1])
}
}
}
}
vararr:Array = [50,20,30,80]
bubbleSort(&arr)
print(arr)
输出结果:[20, 30, 50, 80]
内部函数:默认情况下的参数都是内部参数
外部函数:如果有多个参数的情况,调用者并不知道每个参数的含义,
只能通过查看头文件的形式理解参数的含义
那么能不能和OC一样让调用者直观的知道参数的含义呢?使用外部参数
外部参数只能外部用,函数内部不能使用,函数内部只能使用内部参数
funcdivisionOpertaion1(a:Double, b:Double) ->Double{
returna / b
}
funcdivisionOpertaion2(dividend:Double, divisor:Double) ->Double{
returndividend / divisor
}
funcdivisionOpertaion3(dividend a:Double, divisor b:Double) ->Double{
returna / b
}
print(divisionOpertaion3(dividend:10, divisor:3.5))
funcdivisionOpertaion4(a:Double, divisor b:Double) ->Double{
returna / b
}
print(divisionOpertaion4(10, divisor:3.5))
输出结果:
2.85714285714286
2.85714285714286
funcdivisionOpertaion(dividend:Double, divisor:Double) ->Double{
returndividend / divisor
}
print(divisionOpertaion(10, divisor:3.5))
输出结果:2.85714285714286
默认参数:
可以在定义函数的时候给某个参数赋值,当外部调用没有传递该参数时会自动使用默认值
funcjoinString(s1:String,toString s2:String, jioner s3:String) ->String
{
returns1 + s3 + s2;
}
funcjoinString2(s1:String,toString
s2:String, jioner
s3:String="??") ->String
{
returns1 + s3 + s2;
}
print(joinString2("hi", toString:"beauty"))
输出结果:hi??beauty
如果指定了默认参数,但是确没有声明外部参数时
系统会自动把内部参数名称既作为内部参数也作为外部参数名称
并且在调用时如果需要修改默认参数的值必须写上外部参数名称
funcjoinString3(s1:String,toString
s2:String,
jioner:String="??") ->String
{
returns1 + jioner + s2;
}
print(joinString3("hi", toString:"beauty", jioner:"??"))
输出结果:hi??beauty
在其它语言中默认参数智能出现在参数列表的最后面,但是在Swift中可以出现在任何位置
funcjoinString4(s1:String,
jioner:String="??",
toString s2:String) ->String
{
returns1 + jioner + s2;
}
print(joinString4("hi", jioner:"??", toString:"beauty"))
输出结果:hi??beauty
常量参数和遍历参数:
默认情况下Swift中所有函数的参数都是常量参数
如果想在函数中修改参数,必须在参数前加上var
funcswap(vara:Int,varb:Int)
{
print("交换前a =\(a) b =\(b)")
lettemp = a;
a = b;
b = temp;
print("交换后a =\(a) b =\(b)")
}
swap(10, b:20)
输出结果:
交换前a = 10 b = 20
交换后a = 20 b = 10
inout参数
如果想在函数中修改外界传入的参数
可以将参数的var换成inout,这回会传递参数本身而不是参数的值
funcswap(inouta:Int,inoutb:Int)
{
lettemp = a;
a = b;
b = temp;
}
varx1 =10;
vary1 =20;
print("交换前a =\(x1) b =\(y1)")
swap(&x1, b: &y1)
print("交换后a =\(x1) b =\(y1)")
输出结果:
交换前a = 10 b = 20
交换后a = 20 b = 10
变参函数
如果没有变参函数,并且函数的参数个数又不确定那么只能写多个方法或者用将函数参数改为集合
变参只能放到参数列表的最后一位,变参必须指定数据类型,变参只能是同种类型的数据
funcadd(num1:Int, num2:Int, num3:Int) ->Int
{
letsum = num1 + num2 + num3
returnsum
}
print(add(1, num2:2, num3:3))
输出结果:6
funcadd(nums:[Int]) ->Int
{
varsum =0;
fornuminnums
{
sum += num
}
returnsum
}
print(add([1,2,3]))
输出结果:6
funcadd(nums:Int...) ->Int
{
varsum =0;
fornuminnums
{
sum += num
}
returnsum
}
print(add(1,2,3))
输出结果:6
funcadd(other:Int, nums:Int...) ->Int
{
varsum =0;
fornuminnums
{
sum += num
}
returnsum
}
print(add(99, nums:1,2,3))
输出结果:6
函数类型:
类似于C语言的指向函数的指针
类似于OC语言的block
函数类型是由函数的参数类型和返回值类型组成的
这两个函数的类型是(Int, Int) -> Int
funcsum(a:Int, b:Int) ->Int
{
returna + b;
}
funcsub(a:Int, b:Int) ->Int
{
returna - b;
}
可以利用函数类型定义函数变量和常量
varfuncP:(Int,Int) ->Int=sum
funcP=sub
print(funcP(10,20))
输出结果:-10
funcsum(a:Int, b:Int) ->Int
{
returna + b;
}
funcsub(a:Int, b:Int) ->Int
{
returna - b;
}
函数类型可以作为函数的参数
funccalFunc(a:Int, b:Int,Option:(Int,Int) ->Int) ->Int
{
returnOption(a, b)
}
print(calFunc(10, b:20, Option:sum))
print(calFunc(10, b:20, Option:sub))
输出结果:
30
-10
函数类型可以作为函数返回值
funcmax(a:Int, b:Int) ->Int
{
returna > b ? a : b
}
funcmin(a:Int, b:Int) ->Int
{
returna < b ? a : b
}
funcchooseFunc(getMax:Bool) -> (Int,Int) ->Int
{
returngetMax ?max:min
}
varfuncP2:(Int,Int) ->Int=chooseFunc(false)
print(funcP2(10,20))
输出结果:10
19-闭包,闭包函数回调,尾随闭包,闭包捕获值
闭包:
函数是闭包的一种
类似于OC语言的block
闭包表达式(匿名函数) --能够捕获上下文中的值
语法: in关键字的目的是便于区分返回值和执行语句
闭包表达式的类型和函数的类型一样,是参数加上返回值,也就是in之前的部分
{
(参数) ->返回值类型in
执行语句
}
完整写法
letsay:(String) ->Void= {
(name:String) ->Voidin
print("hi\(name)")
}
say("lzh")
输出结果:hi lzh
没有返回值写法
letsay:(String) ->Void= {
(name:String)in
print("hi\(name)")
}
say("lzh")
输出结果:hi lzh
没有参数没有返回值写法
letsay:() ->Void= {
print("hi xmg")
}
say()
输出结果:hi xmg
闭包表达式作为回调函数
传统数组排序写法:
缺点:不一定是小到大,不一定是全部比较,有可能只比较个位数
所以,如何比较可以交给调用者决定
funcbubbleSort(inoutarray:[Int])
{
letcount = array.count;
forvari =1; i < count; i++
{
forvarj =0; j < (count - i); j++
{
ifarray[j] > array[j +1]
{
lettemp = array[j]
array[j] = array[j +1]
array[j +1] = temp
}
}
}
}
闭包写法:
funcbubbleSort(inoutarray:[Int], cmp: (Int,Int) ->Int)
{
letcount = array.count;
forvari =1; i < count; i++
{
forvarj =0; j < (count - i); j++
{
ifcmp(array[j], array[j +1]) == -1
{
lettemp = array[j]
array[j] = array[j +1]
array[j +1] = temp
}
}
}
}
letcmp = {
(a:Int, b:Int) ->Intin
ifa > b{
return1;
}elseifa < b
{
return-1;
}else
{
return0;
}
}
vararr:Array = [31,13,52,84,5]
bubbleSort(&arr, cmp:cmp)
print(arr)
输出结果:
[84, 52, 31, 13, 5]
闭包作为参数传递
vararr:Array = [31,13,52,84,5]
bubbleSort(&arr, cmp: {
(a:Int, b:Int) ->Intin
ifa > b{
return1;
}elseifa < b
{
return-1;
}else
{
return0;
}
})
print(arr)
输出结果:
[84, 52, 31, 13, 5]
尾随闭包:
如果闭包是最后一个参数,可以直接将闭包写到参数列表后面
这样可以提高阅读性.称之为尾随闭包
bubbleSort(&arr) {
(a:Int, b:Int) ->Intin
ifa > b{
return1;
}elseifa < b
{
return-1;
}else
{
return0;
}
}
闭包表达式优化
1.类型优化,由于函数中已经声明了闭包参数的类型
所以传入的实参可以不用写类型
2.返回值优化,同理由于函数中已经声明了闭包的返回值类型
所以传入的实参可以不用写类型
3.参数优化, swift可以使用$索引的方式来访问闭包的参数,默认从0开始
bubbleSort(&arr){
(a , b) -> Int in
(a , b) in
if$0 > $1{
return1;
}elseif$0 < $1
{
return-1;
}else
{
return0;
}
}
如果只有一条语句可以省略return
lethehe = {
"我是xmg"
}
闭包捕获值
funcgetIncFunc() -> (Int) ->Int
{
varmax =10
funcincFunc(x :Int) ->Int{
print("incFunc函数结束")
max++
returnmax + x
}
当执行到这一句时inc参数就应该被释放了
但是由于在内部函数中使用到了它,所以它被捕获了
同理,当执行完这一句时max变量就被释放了
但是由于在内部函数中使用到了它,所以它被捕获了
print("getIncFunc函数结束")
returnincFunc
}
被捕获的值会和与之对应的方法绑定在一起
同一个方法中的变量会被绑定到不同的方法中
letincFunc =getIncFunc()
print("---------")
print(incFunc(5))
print("---------")
print(incFunc(5))
输出结果:
getIncFunc函数结束
---------
incFunc函数结束
16
---------
incFunc函数结束
17
letincFunc2 =getIncFunc(5)
print(incFunc2(5))
输出结果:
getIncFunc函数结束
incFunc函数结束
16
Swift枚举:
Swift中的枚举比OC中的枚举强大,因为Swift中的枚举是一等类型,
它可以像类和结构体一样增加属性和方法
格式:
enum Method{
case枚举值
}
enumMethod{
case Add
case Sub
case Mul
case Div
可以连在一起写
caseAdd, Sub, Mul, Div
}
可以使用枚举类型变量或常量接收枚举值
varm:Method= .Add
注意:如果变量或常量没有指定类型,那么前面必须加上该值属于哪个枚举类型
varm1 =Method.Add
利用Switch匹配
注意:如果case中包含了所有的值,可以不写default.
如果case中没有包含枚举中所有的值,必须写default
switch(Method.Add){
caseMethod.Add:
print("加法")
caseMethod.Sub:
print("减法")
caseMethod.Mul:
print("除法")
caseMethod.Div:
print("乘法")
default:
print("都不是")
}
原始值:
OC中枚举的本质就是整数,所以OC中的枚举是有原始值的,默认是从0开始
而Swift中的枚举默认是没有原始值的,但是可以在定义时告诉系统让枚举有原始值
enum Method:枚举值原始值类型{
case枚举值
}
enumMethod2:Int{
可以连在一起写
caseAdd, Sub, Mul, Div
}
和OC中的枚举一样,也可以指定原始值,后面的值默认+1
enumMethod3:Int{
caseAdd =5, Sub, Mul, Div
}
Swift中的枚举除了可以指定整形以外还可以指定其它类型,
但是如果指定其它类型,必须给所有枚举值赋值,因为不能自动递增
enumMethod4:Double{
可以连在一起写
caseAdd =5.0, Sub =6.0, Mul =6.1, Div =8.0
}
rawValue代表将枚举值转换为原始值,注意老版本中转换为原始值的方法名叫toRaw
Method4.Sub.rawValue
原始值转换为枚举值
enumMethod5:String{
caseAdd ="add", Sub ="sub", Mul ="mul", Div ="div"
}
通过原始值创建枚举值
注意:
1.原始值区分大小写
2.返回的是一个可选值,因为原始值对应的枚举值不一定存在
3.老版本中为fromRaw("add")
letm2 =Method5(rawValue:"add")
print(m2)
funcchooseMethod(op:String)
{
由于返回是可选类型,所以有可能为nil,最好使用可选绑定
ifletopE =Method5(rawValue: op){
switch(opE){
case.Add:
print("加法")
case.Sub:
print("减法")
case.Mul:
print("除法")
case.Div:
print("乘法")
}
}
}
枚举相关值:
可以让枚举值对应的原始值不是唯一的,而是一个变量.
每一个枚举可以是在某种模式下的一些特定值
enumlineSegmentDescriptor{
caseStartAndEndPattern(start:Double, end:Double)
caseStartAndLengthPattern(start: Double, length:Double)
}
varlsd =lineSegmentDescriptor.StartAndLengthPattern(start:0.0, length:100.0)
lsd=lineSegmentDescriptor.StartAndEndPattern(start:0.0, end:50.0)
利用switch提取枚举关联值
switchlsd
{
caselet.StartAndEndPattern(s, e):
print("start =\(s) end =\(e)")
case.StartAndLengthPattern(lets,letl):
print("start =\(s) lenght =\(l)")
}
结构体:
结构体是用于封装不同或相同类型的数据的
Swift中的结构体是一类类型,可以定义属性和方法(甚至构造方法和析构方法等)
格式:
struct结构体名称{
结构体属性和方法
}
structRect {
varwidth:Double=0.0
varheight:Double=0.0
}
如果结构体的属性有默认值,可以直接使用()构造一个结构体
如果结构体的属性没有默认值,必须使用逐一构造器实例化结构体
varr =Rect()
print("width =\(r.width) height =\(r.height)")
输出结果:width = 0.0 height = 0.0
结构体属性的访问使用.语法
varr =Rect()
r.width=100
r.height=99
print("width =\(r.width) height =\(r.height)")
输出结果:width = 100.0 height = 99.0
结构体构造器
Swift中的结构体和类跟其它面向对象语言一样都有构造函数,而OC是没有的
Swift要求实例化一个结构体或类的时候,所有的成员变量都必须有初始值,
构造函数的意义就是用于初始化所有成员变量的,而不是分配内存,分配内存是系统帮我们做的.
如果结构体中的所有属性都有默认值,可以调用()构造一个结构体实例
如果结构体中的属性没有默认值,可以自定义构造器,并在构造器中给所有的属性赋值
其实结构体有一个默认的逐一构造器,用于在初始化时给所有属性赋值
structRect2 {
varwidth:Double
varheight:Double=0.0
}
逐一构造器
varr1 =Rect2(width:10.0, height:10.0);
错误写法,顺序必须和结构体中成员的顺序一致
var r1 = Rect2(height: 10.0, width: 10.0);
错误写法,必须包含所有成员
var r1 = Rect2(height: 10.0);
结构体中定义成员方法
在C和OC中结构体只有属性,而Swift中结构体中还可以定义方法
structRect {
varwidth:Double
varheight:Double=0.0
给结构体定义一个方法,该方法属于该结构体
结构体中的成员方法必须使用某个实例调用
成员方法可以访问成员属性
funcgetWidth() ->Double{
returnwidth
}
}
varr =Rect(width:10.0, height:20.0)
结构体中的成员方法是和某个实例对象绑定在一起的,
所以谁调用,方法中访问的属性就属于谁
print(r.getWidth())
输出结果:10.0
varr1 =Rect(width:30.0, height:20.0)
print(r1.getWidth())
输出结果:30.0
结构体是值类型
structRect {
varwidth:Double
varheight:Double=0.0
funcshow() ->Void{
print("width =\(width) height =\(height)")
}
}
varr1 =Rect(width:10.0, height:10.0)
varr2 =r1
r1.show()
r2.show()
r1.width=20.0
结构体是值类型,结构体之间的赋值其实是将r1中的值完全拷贝一份到r2中,
所以他们是两个不同的实例
r1.show()
r2.show()
输出结果:
width = 10.0 height = 10.0
width = 10.0 height = 10.0
width = 20.0 height = 10.0
width = 10.0 height = 10.0
类的基本定义
Swift中的结构体和类非常相似,但是又有不同之处
类是具有相同属性和方法的抽象
格式:
class类名称{
类的属性和方法
}
classRect {
varwidth:Double=0.0
varheight:Double=0.0
funcshow() ->Void{
print("width =\(width) height =\(height)")
}
}
类没有逐一构造器
var r1 = Rect(width: 10.0, height: 10.0)
varr1 =Rect()
r1.show()
varr2 =r1
r2.show()
输出结果:
width = 0.0 height = 0.0
width = 0.0 height = 0.0
类是引用类型,类之间的赋值其实是将r2指向了r1的存储空间
所以他们是两个只想同一块存储空间,修改其中一个会影响到另外一个
r1.width=99
r1.show()
r2.show()
输出结果:
width = 99.0 height = 0.0
width = 99.0 height = 0.0
恒等运算符
用于判断是否是同一个实例,也就是是否指向同一块存储空间
=== !==
varr3 =Rect()
ifr1===r3
{
print("指向同一块存储空间")
}
输出结果:
指向不同的存储空间
存储属性
Swift中的存储属性就是以前学习OC中的普通属性
在结构体或者类中定义的属性,默认就是存储属性
structPerson {
varname:String
varage:Int
}
varp:Person=Person(name:"lzh", age:30)
p.name="gxq"
p.age=50
常量存储属性
常量存储属性只能在定义时或构造时修改
构造好一个对象之后不能对常量存储属性进行修改
structPerson {
varname:String
varage:Int
letcard:String身份证
}
varp:Person=Person(name:"gaowei", age:30, card:"123456")
p.name="gxq"
p.age=50
构造好对象之后不能修改常量存储属性
以下写法是错误的
p.card = "56789"
结构体和类常量与存储属性的关系
结构体和枚举是值类型
类是引用类型
structPerson {
varname:String
varage:Int
}
letp:Person=Person(name:"lzh", age:30)
因为结构体是值类型,所以不能修改结构体常量中的属性
不能修改结构体/枚举常量对象中的值,因为他指向的对象是一个常量
以下写法错误
p.name =“gxq"
不能修改结构体常量对象的值
以下写法错误
p=Person(name:"gxq", age:50)
classPerson {
varname:String="lnj"
varage:Int=30
}
letp:Person=Person()
可以修改类常量中的值,因为他指向的对象不是一个常量
p.name=“lzh"
不可以修改类常量的指向
以下写法是错误的
p = Person4()
延迟存储属性
Swift语言中所有的存储属性必须有初始值,
也就是当构造完一个对象后,对象中所有的存储属性必须有初始值
但是也有例外
其中延迟存储属性可以将属性的初始化推迟到该属性第一次被调用的时候
懒加载应用场景:
1.有可能不会用到
2.依赖于其它值
classLine {
varstart:Double=0.0
varend:Double=0.0
如果不是lazy属性,定义的时候对象还没有初始化,所以不能访问self
如果加上lazy,代表使用时才会加载,也就是使用到length属性时才会调用self
而访问一个类的属性必须通过对象方法
所以访问时对象已经初始化完成了,可以使用self
lazyvarlength:Double=self.getLenght()
通过闭包懒加载
lazyvarcontainer:Array = {
print("懒加载")
vararrM = []
returnarrMas[AnyObject]
}()
funcgetLenght() ->Double
{
print("懒加载")
returnend-start
}
}
varline =Line()
line.end=150.0
print("创建对象完毕")
print(line.length)
vararrM =line.container
arrM.append("1")
arrM.append(5)
print(arrM)
输出结果:
创建对象完毕
懒加载
150.0
懒加载
[1, 5]
计算属性
1.Swift中的计算属性不直接存储值
跟存储属性不同,没有任何的"后端存储与之对应"
2.计算属性用于计算,可以实现setter和getter这两种计算方法
3.枚举不可以有存储属性,但是允许有计算属性
setter对象.属性=值
getter var value =对象.属性
structRect {
varorigion: (x:Double, y:Double) = (0,0)
varsize: (w:Double, h:Double) = (0,0)
由于center的值是通过起点和宽高计算出来的,所以没有必要提供一个存储属性
varcenter: (x:Double, y:Double) {
get{
return(origion.x +size.w/2,origion.y +size.h/2)
}
set{
注意:计算属性不具备存储功能,所以不能给计算属性赋值
如果赋值会发生运行时错误
注意: setter可以自己传递一个参数,也可以使用系统默认的参数newValue
如果要使用系统自带的参数,必须删除自定义参数
origion.x = newValue.x -size.w /2
origion.y = newValue.y -size.h /2
}
}
}
varr =Rect()
r.origion= (0,0)
r.size= (100,100)
print("center.x =\(r.center.x) center.y =\(r.center.y)")
输出结果:center.x = 50.0 center.y = 50.0
r.center= (100,100)
print("origion.x =\(r.origion.x) origion.y =\(r.origion.y)")
输出结果:origion.x = 50.0 origion.y = 50.0
print("center.x =\(r.center.x) center.y =\(r.center.y)")
输出结果:center.x = 100.0 center.y = 100.0
只读计算属性
对应OC中的readonly属性
所谓的只读属性就是只提供了getter方法,没有提供setter方法
classLine {
varstart:Double=0.0
varend:Double=0.0
只读属性,只读属性必须是变量var,不能是常量let
例如想获取长度
只能通过计算获得,而不需要外界设置,可以设置为只读计算属性
varlength:Double{
只读属性的简写,可以省略get{}
returnend-start
}
}
varline =Line()
line.end=100
print(line.length)
输出结果:100.0
属性观察器
类似OC中的KVO
可以用于监听属性什么时候被修改,只有属性被修改才会调用
有两种属性观察器:
1.willSet,在设置新值之前调用
2.didSet,在设置新值之后调用
可以直接为除计算属性和lazy属性之外的存储属性添加属性观察器
但是可以在继承类中为父类的计算属性提供属性观察器
因为在计算属性中也可以监听到属性的改变
所以给计算属性添加属性观察器没有任何意义
classLine {
varstart:Double=0.0{
willSet{
print("willSet newValue =\(newValue)")
}
didSet{
print("didSet oldValue =\(oldValue)")
}
}
varend:Double=0.0
}
varl =Line()
l.start=10.0
输出结果:
willSet newValue = 10.0
didSet oldValue = 0.0
类属性
在结构体和枚举中用static
在类中使用class,并且类中不允许将存储属性设置为类属性
structPerson {
普通的属性是每个对象一份
varname:String=“lzh"
类属性是素有对象共用一份
staticvargender:String="man"
staticvarage:Int{
return30
}
funcshow()
{
print("gender =\(Person.gender) name =\(name)")
}
}
varp =Person()
print("gender =\(Person.gender)")
输出结果:gender = man
varp1 =Person()
类属性是所有对象共用一份
print("gender =\(Person.gender)")
p.show()
输出结果:
gender = man
gender = man name = lzh
可以将计算属性设置为类属性
print("age =\(Person.age)")
输出结果:age = 30
classPerson {
普通的属性是每个对象一份
varname:String="lnj"
类中不允许将存储属性定义为类属性
下面为错误写法
class var gender:String = "man"
类中只能将计算属性定义为类属性
classvarage:Int{
return30
}
funcshow()
{
print("age =\(Person.age)")
}
}
varp =Person()
print("age =\(Person.age)")
p.show()
输出结果:
age = 30
age = 30
方法
隶属于每一个类或结构体的函数称之为方法:
方法分为类方法和实例方法,对应OC中的+ -方法
实例方法:实例方法一定是通过对象来调用的,实例方法隶属于某一个类
classPerson {
var_name:String="lzh"
var_age:Int=30
实例方法一定是通过对象来调用的,实例方法隶属于某一个类
funcsetName(name:String,age:Int)
如果不希望某个参数作为外部参数,可以在参数前面加上_,忽略外部参数
funcsetName(name:String,_age:Int)
{
_name= name
_age= age
}
funcshow()
{
print("name =\(_name) age =\(_age)")
}
}
varp =Person()
由于第一个参数可以通过方法名称指定,所以默认第一个参数不作为外部参数
p.setName("zs", age: 88)
可以在参数前面加上_,忽略外部参数
p.setName("zs",88)
p.show()
输出结果:name = zs age = 88
self关键字
Swift中的self和OC中的self基本一样. self指当前对象
如果self在对象方法中代表当前对象.但是在类方法中没有self
classPerson {
varname:String=“lzh"
varage:Int=30
当参数名称和属性名称一模一样时,
无法区分哪个是参数哪个是属性
这个时候可以通过self明确的来区分参数和属性
funcsetName(name:String, age:Int)
{
默认情况下, _name和_age前面有一个默认的self关键字,
因为所有变量都需要先定义再使用
而setName方法中并没有定义过_name和_age,
而是在属性中定义的,所以setName中访问的其实是属性,
编译器默认帮我们在前面加了一个self.
_name = name
_age = age
self.name= name
self.age= age
}
funcshow()
{
print("name =\(name) age =\(age)")
}
}
varp =Person()
p.setName("xq", age:20)
p.show()
输出结果:name = xq age = 20
mutating方法
值类型(结构体和枚举)默认方法是不可以修改属性的
如果需要修改属性
需要在方法前加上mutating关键字,让该方法变为一个改变方法
structPerson {
varname:String="lzh"
varage:Int=30
值类型(结构体和枚举)默认方法是不可以修改属性的
如果需要修改属性
需要在方法前加上mutating关键字,让该方法变为一个改变方法
注意:类不需要,因为类的实例方法默认就可以修改
mutatingfuncsetName(name:String, age:Int)
{
self.name= name
self.age= age
}
funcshow()
{
print("name =\(name) age =\(age)")
}
}
varp =Person()
p.setName("zs", age:99)
p.show()
输出结果:name = zs age = 99
enumLightSwitch{
caseOFF, ON
mutatingfuncnext()
{
switchself{
caseOFF:
self=ON
caseON:
self=OFF
}
}
}
varls:LightSwitch=LightSwitch.OFF
ifls==LightSwitch.OFF
{
print("off")
}
ls.next()
ifls==LightSwitch.ON
{
print("on")
}
输出结果:
off
on
类方法:
和类属性一样通过类名来调用
类方法通过static关键字(结构体/枚举), class(类)
类方法中不存在self
structPerson {
varname:String=“lzh"
staticvarcard:String="123456"
funcshow()
{
print("name =\(self.name) card =\(Person.card)")
}
staticfuncstaticShow()
{
类方法中没有self
print("name = \(self.name) card = \(Person.card)")
静态方法对应OC中的+号方法,和OC一样在类方法中不能访问非静态属性
print("card =\(Person.card)")
}
}
varp =Person()
p.show()
Person.staticShow()
输出结果:
name = lzh card = 123456
card = 123456
classPerson {
varname:String="lzh"
classvarcard:String{
return"123456"
}
funcshow()
{
print("name =\(self.name) card =\(Person.card)")
}
classfuncstaticShow()
{
类方法中没有self
print("name = \(self.name) card = \(Person.card)")
静态方法对应OC中的+号方法,和OC一样在类方法中不能访问非静态属性
print("card =\(Person.card)")
}
}
varp =Person()
p.show()
Person.staticShow()
输出结果:
name = lzh card = 123456
card = 123456
subscripts(下标):
访问对象中数据的快捷方式
所谓下标脚本语法就是能够通过,实例[索引值]来访问实例中的数据
类似于以前我们访问数字和字典,其实Swift中的数组和字典就是一个结构体
structStudent {
varname:String="lzh"
varmath:Double=99.0
varchinese:Double=99.0
varenglish:Double=99.0
funcscore(course:String) ->Double?
{
switchcourse{
case"math":
returnmath
case"chinese":
returnchinese
case"english":
returnenglish
default:
returnnil
}
}
要想实现下标访问,必须实现subscript方法
如果想要通过下标访问,必须实现get方法
如果想要通过下表赋值,必须实现set方法
subscript(course:String) ->Double?{
get{
switchcourse{
case"math":
returnmath
case"chinese":
returnchinese
case"english":
returnenglish
default:
returnnil
}
}
set{
switchcourse{
case"math":
因为返回的是可选类型
math= newValue!
case"chinese":
chinese= newValue!
case"english":
english= newValue!
default:
print("not found")
}
}
}
}
varstu =Student(name:"zs",
math:99.0,
chinese:88.0,
english:10.0)
print(stu.score("math"))
输出结果:Optional(99.0)
stu["chinese"]=100.0
print(stu["chinese"])
输出结果:Optional(100.0)
继承语法
继承是面向对象最显著的一个特性,继承是从已经有的类中派生出新的类
新的类能够继承已有类的属性和方法,并能扩展新的能力
术语:基类(父类,超类),派生类(子类,继承类)
语法:
class子类:父类{
}
继承优点:代码重用
继承缺点:增加程序耦合度,父类改变会影响子类
注意:Swift和OC一样没有多继承
classMan {
varname:String="lzh"
varage:Int=10
funcsleep(){
print("睡觉")
}
}
classSuperMan:Man{
varpower:Int=100
funsfly(){
子类可以继承父类的属性
print("飞\(name)\(age)")
}
}
varm =Man()
m.sleep()
父类不可以使用子类的方法
m.fly()
输出结果:睡觉
varsm =SuperMan()
子类可以继承父类的方法
sm.sleep()
sm.fly()
输出结果:
睡觉
飞lzh 10
super关键字:
派生类中可以通过super关键字来引用父类的属性和方法
classMan {
varname:String="lzh"
varage:Int=30
funcsleep(){
print("睡觉")
}
}
classSuperMan:Man{
varpower:Int=100
funceat()
{
print("吃饭")
}
funcfly(){
子类可以继承父类的属性
print("飞\(super.name)\(super.age)")
}
funceatAndSleep()
{
eat()
super.sleep()
如果没有写super,那么会先在当前类中查找,如果找不到再去父类中查找
如果写了super,会直接去父类中查找
}
}
varsm =SuperMan()
sm.eatAndSleep()
输出结果:
吃饭
睡觉
方法重写: override
重写父类方法,必须加上override关键字
classMan {
varname:String="lzh"
varage:Int=10
funcsleep(){
print("父类睡觉")
}
}
classSuperMan:Man{
varpower:Int=100
override关键字主要是为了明确表示重写父类方法,
所以如果要重写父类方法,必须加上override关键字
overridefuncsleep() {
sleep()不能这样写,会导致递归
super.sleep()
print("子类睡觉")
}
funceat()
{
print("吃饭")
}
funcfly(){
子类可以继承父类的属性
print("飞\(super.name)\(super.age)")
}
funceatAndSleep()
{
eat()
sleep()
}
}
varsm =SuperMan()
通过子类调用,优先调用子类重写的方法
sm.sleep()
输出结果:
父类睡觉
子类睡觉
sm.eatAndSleep()
输出结果:
吃饭
父类睡觉
子类睡觉
重写属性
无论是存储属性还是计算属性,都只能重写为计算属性
classMan {
varname:String="lzh"存储属性
varage:Int{计算属性
get{
return30
}
set{
print("man new age\(newValue)")
}
}
funcsleep(){
print("睡觉")
}
}
classSuperMan:Man{
varpower:Int=100
可以将父类的存储属性重写为计算属性
但不可以将父类的存储属性又重写为存储属性,因为这样没有意义
override var name:String = "zs"
overridevarname:String{
get{
return"zs"
}
set{
print("SuperMan new name\(newValue)")
}
}
可以将父类的计算属性重写为计算属性,同样不能重写为存储属性
overridevarage:Int{计算属性
get{
return30
}
set{
print("superMan new age\(newValue)")
}
}
}
letsm =SuperMan()
通过子类对象来调用重写的属性或者方法,肯定会调用子类中重写的版本
sm.name="xxx"
sm.age=50
输出结果:
SuperMan new name xxx
superMan new age 50
重写属性的限制
1.读写计算属性/存储属性,是否可以重写为只读计算属性? (权限变小)不可以
2.只读计算属性,是否可以在重写时变成读写计算属性? (权限变大)可以
classMan {
varname:String="lzh"存储属性
varage:Int{计算属性
get{
return30
}
set{
print("man new age\(newValue)")
}
}
funcsleep(){
print("睡觉")
}
}
classSuperMan:Man{
varpower:Int=100
overridevarname:String{
get{
return"zs"
}
set{
print("SuperMan new name\(newValue)")
}
}
overridevarage:Int{计算属性
get{
return30
}
set{
print("superMan new age\(newValue)")
}
}
}
重写属性观察器
只能给非lazy属性的变量存储属性设定属性观察器,
不能给计算属性设置属性观察器,给计算属性设置属性观察器没有意义
属性观察器限制:
1.不能在子类中重写父类只读的存储属性
2.不能给lazy的属性设置属性观察器
classMan {
varname:String="lzh"
varage:Int=0{存储属性
willSet{
print("super new\(newValue)")
}
didSet{
print("super new\(oldValue)")
}
}
varheight:Double{
get{
print("super get")
return10.0
}
set{
print("super set")
}
}
}
classSuperMan:Man{
可以在子类中重写父类的存储属性为属性观察器
overridevarname:String{
willSet{
print("new\(newValue)")
}
didSet{
print("old\(oldValue)")
}
}
可以在子类中重写父类的属性观察器
overridevarage:Int{
willSet{
print("child new\(newValue)")
}
didSet{
print("child old\(oldValue)")
}
}
可以在子类重写父类的计算属性为属性观察器
overridevarheight:Double{
willSet{
print("child height")
}
didSet{
print("child height")
}
}
}
varm =SuperMan()
m.age=55
输出结果:
child new 55
super new 55
super new 0
child old 0
print(m.age)
输出结果:55
m.height=20.0
输出结果:
super get
child height
super set
child height
final关键字
利用final关键字防止重写
final关键字既可以修饰属性,也可以修饰方法,并且还可以修饰类
被final关键字修饰的属性和方法不能被重写
被final关键字修饰的类不能被继承
finalclassMan {
finalvarname:String="lzh"
finalvarage:Int=0{//存储属性
willSet{
print("super new\(newValue)")
}
didSet{
print("super new\(oldValue)")
}
}
finalvarheight:Double{
get{
print("super get")
return10.0
}
set{
print("super set")
}
}
finalfunceat(){
print("吃饭")
}
}
构造方法
作用:对实例对象的内容进行初始化
Swift要求类或者结构体中的存储属性(非lazy的)在对象构造完毕后要有初始化值
语法:
init(参数列表){初始化代码}
注意:
1.在Swift中类/结构体/枚举都需要构造方法
2.构造方法的作用仅仅是用于初始化属性,而不是分配内容,分配内存是系统帮我们做的
3.构造方法是隐式调用的,通过类名称()形式创建一个对象就会隐式调用init()构造方法
4.如果所有的存储属性都有默认值,可以不提供构造方法,系统会提供一个隐式的构造方法
5.如果存储属性可以提供缺省,那么提倡大家使用设置缺省值的方式,
这样可以简化代码(不用自定义构造方法,不用写存储属性类型)
classPerson {
varname:String="lzh"
varage:Int
funcdescription() ->String{
return"name =\(name) age =\(age)"
}
init()
{
print("init")
age=30
}
}
1.分配内存
2.初始化name和age
3.构造方法是隐式调用的
varp =Person()
p.description()显示调用
输出结果:init
带参数的构造方法
classPerson {
varname:String
varage:Int
funcdescription() ->String{
return"name =\(name) age =\(age)"
}
构造方法的内部参数,默认也是外部参数
而函数的内部参数默认不会当做外部参数
而方法的内部参数,从第二个开始才会当做外部参数
init(name:String, age:Int)
构造方法对属性的顺序没有要求,
只要保证对象构造完时所有存储属性被初始化即可
init(age:Int, name:String)
{
self.name= name
self.age= age
}
funcsetName(name:String, age:Int)
{
}
}
varp =Person(age:30, name:"lzh")
p.setName("lzh", age:30)
funcsetName(name:String, age:Int)
{
}
p.setName("lzh", age:30)
常量存储属性与构造方法
常量存储属性只能通过缺省值或在构造方法中被修改
其它任何地方都不能修改
classPerson {
varname:String="lzh"
letage:Int
init(age:Int, name:String)
{
self.age= age
self.name= name
}
funcdescription() ->String{
return"name =\(name) age =\(age)"
}
}
varp =Person(age:30, name:"zs")
print(p3.description())
输出结果:name = zs age = 30
常量存储属性初始化之后不允许被修改
p.age =10
可选属性与构造方法
classCar {
letname:String
init(name:String)
{
self.name= name
}
}
classPerson {
letname:String
varage:Int
varcar:Car?
可选值存储属性可以不再构造方法中初始化,
也就是说可选值在对象构造完毕后不用初始化
其实如果不对可选存储属性进行初始化,默认就是nil
init(age:Int, name:String)
{
self.age= age
self.name= name
}
funcdescription() ->String{
return"name =\(name) age =\(age) car =\(car)"
}
}
varp =Person(age:10, name:"lzh")
print(p.description())
输出结果:name = lzh age = 10 car = nil
结构体构造方法
structRect{
此时即没有提供缺省值,也没有提供构造方法,但是编译通过
因为默认情况下,结构体会给结构体提供一个默认的成员逐一构造器
varwidth:Double=0.0
varheight:Double=0.0
系统默认会提供一个类似的方法
init(width:Double, height:Double)
{
self.width = width
self.height = height
}
init()
{
self.width = 0.0
self.height = 0.0
}
}
注意:
1.在类中默认是没有逐一构造器的
2.如果在结构体中自定义了构造方法,那么系统不会生成默认的逐一构造器
3.如果给存储属性提供了缺省值,系统还是会提供默认的逐一构造器
4.如果给存储属性提供了缺省值,可以使用不带参数的方法初始化结构体
varr =Rect()
print("width=\(r.width),height=\(r.height)")
输出结果:width=0.0,height=0.0
varr =Rect(width:10, height:20)
print("width=\(r.width),height=\(r.height)")
输出结果:width=10.0,height=20.0
"值类型"的构造器代理
构造器代理:构造方法之间的相互调用
构造方法可以调用其他构造方法来完成实例的构造,称之为构造器代理
好处:减少构造方法之间的重复代码
structRect {
varwidth:Double
varheight:Double
init(width:Double, height:Double)
{
self.width= width
self.height= height
}
init()
{
self.width = 0
self.height = 0
构造器代理
self.init(width:0, height:0)
}
funcshow(){
print("width =\(width) height =\(height)")
}
}
varr =Rect()
r.show()
输出结果:width = 0.0 height = 0.0
varr1 =Rect(width:100, height:100)
r1.show()
输出结果:
width = 100.0 height = 100.0
通过闭包或者全局函数/类方法设置存储属性的缺省值
如果需要经过计算,或者需要进行一些额外的操作才能确定初始值时
就可以通过闭包或全局函数设置存储属性的缺省值
funcgetValue() ->Int
{
print("getValue")
return55
}
classPerson {
varname:String
系统在初始化的时候会隐式执行闭包,
将闭包的执行结果赋值给存储属性
注意:闭包后面一定要有(),代表执行闭包
varage:Int= {
() -> Int in返回值可以省略,
默认返回值的类型就是存储属性的类型
print("age闭包")
return30
}()
lazyvarheight:Double= {
print("lazy闭包")
return175.0
}()
varage2:Int=getValue()
varage3:Int=Person.getValue2()
不能这样写,因为调用方法时对象还没有初始化完毕
self只有当所有的存储属性都初始化完毕之后才可以用
var age3:Int = self.getValue3()
init(name:String)
{
print("init")
self.name= name
}
classfuncgetValue2() ->Int{
print("class getValue2")
return100
}
funcgetValue3() ->Int
{
return88
}
}
varp =Person(name:"lzh")
懒加载是用到时才执行,而闭包赋值是初始化时就会执行
print(p.height)
输出结果:
age闭包
getValue
class getValue2
init
lazy闭包
175.0
指定构造与便利构造方法
classPerson {
varname:String
varage:Int
指定构造方法都是以init开头的
init(name:String, age:Int)
{
print("init")
self.name= name
self.age= age
}
如果是值类型没问题,称之为构造器代理
但如果是引用类型会报错,需要在前面加上convenience关键字.
被convenience关键字修饰的构造方法称之为便利构造器,
通过调用其它构造方法来初始化.
反而言之,便利构造器中一定是调用其它构造方法初始化的
一定要出现self.init
convenienceinit()
{
print("convenience init")
self.init(name:”lzh", age:30)
}
类可以拥有多个构造方法
init(name:String)
{
print("init name")
self.name= name
self.age=0
不能在指定构造方法中调用便利构造方法
也就是说指定构造方法中不能出现self.init
self.init()
}
convenienceinit(age:Int)
{
print("convenience init age")
可以在便利构造器中调用指定构造器
self.init(name:”lzh", age:30)
以在便利构造器中调用便利构造器
self.init()
}
便利构造器不能和指定构造器同名
convenience init(name:String)
{
}
}
varp =Person()
输出结果:
convenience init
init
varp1 =Person(age:10)
输出结果:
convenience init age
convenience init
init
varp2 =Person(name:"lzh")
输出结果:
init name
varp3 =Person(name:"lzh", age:20)
输出结果:
init
派生类的构造方法
classMan {
varname:String
指定构造方法
init(name:String){
print("Man init")
self.name= name
}
便利构造方法
convenienceinit(){
print("Man convenience init")
self.init(name:"convenience-lzh")
}
}
classSuperMan:Man{
varage:Int
注意:
1.默认情况下构造方法不会被继承
2.基类的存储属性只能通过基类的构造方法初始化
3.初始化存储属性时必须先初始化当前类再初始化父类
4.不能通过便利构造方法初始化父类,只能通过调用指定构造方法初始化父类
指定构造器
init(age:Int){
self.age= age
super.init(name:"lzh")
不能通过便利构造方法初始化父类,只能通过调用指定构造方法初始化父类
以下写法是错误的
super.init()
}
funcshow(){
print("age =\(self.age) name=\(self.name)")
}
}
varp =Man()
输出结果:
Man convenience init
Man init
varp =SuperMan(age:10)
输出结果:
SuperMan init
Man init
构造器间的调用规则
>指定构造器必须调用其直接父类的"指定构造器"
>便利构造器必须调用同类中的其它构造器(指定或便利)
>便利构造器必须最终以调用一个指定构造器结束
(无论调用的是指定还是便利,最终肯定会调用一个指定构造器)
*指定构造器总是向上代理(父类)
*便利构造器总是横向代理(当前类)
classMan {
varname:String
指定构造方法
init(name:String){
print("Man->init")
self.name= name
}
便利构造方法
convenienceinit(){
print("Man->convenience init")
self.init(name:"lzh")
}
}
classSuperMan:Man{
varage:Int
指定构造器
init(age:Int){
print("SuperMan->init")
self.age= age
super.init(name:"lzh")
}
convenienceinit(){
print("SuperMan->convenience init")
self.init(age:30)
}
convenienceinit(name:String, age:Int){
print("SuperMan->convenience init name age")
调用子类构造器一定能够初始化所有属性
便利构造器中只能通过self.init来初始化,不能使用super.init
因为调用父类构造器不一定能完全初始化所有属性(子类特有)
super.init(name: “lzh")
self.init()
}
funcshow(){
print("name =\(self.name) age =\(self.age)")
}
}
varp =SuperMan()
p.show()
输出结果:
SuperMan->convenience init
SuperMan->init
Man->init
name = lzh age = 30
varp =SuperMan(age:10)
p.show()
输出结果:
SuperMan->init
Man->init
name = lzh age = 10
varp =SuperMan(name:"lzh", age:20)
p.show()
输出结果:
SuperMan->convenience init name age
SuperMan->convenience init
SuperMan->init
Man->init
name = lzh age = 30
两段式构造
构造过程可以划分为两个阶段
1.确保当前类和父类所有存储属性都被初始化
2.做一些其它初始化操作
好处: 1.可以防止属性在被初始化之前访问
2.可以防止属性被另外一个构造器意外赋值
注意:构造器的初始化永远是在所有类的第一阶段初始化完毕之后才会开始第二阶段
编译器安全检查:
1.必须先初始化子类特有属性,再向上代理父类指定构造方法初始化父类属性
2.只能在调用完父类指定构造器后才能访问父类属性
3.在便利构造器中,必须先调用同类其它构造方法后才能访问属性
4.第一阶段完成前不能访问父类属性/也不能引用self和调用任何实例方法
classMan {
varname:String
指定构造方法
init(name:String){
self.name= name
}
便利构造方法
convenienceinit(){
self.init(name:"lnj")
}
}
classSuperMan:Man{
varage:Int
指定构造器
init(age:Int){
print("SuperMan第一阶段开始")
对子类引入的属性初始化
self.age= age
代码会报错,因为调用self.name之前还没有对父类的name进行初始化
即便在这个地方修改,也会被后面的初始化语句覆盖
if (age > 30){
self.name = "zs"
}
对父类引入的属性进行初始化
super.init(name:"lzh")
print("SuperMan第二阶段开始")
ifage >30{
self.name="zs"
}
}
}
classMonkeyMan:SuperMan{
varheight:Double
init(height:Double){
print("MonkeyMan第一阶段开始")
对子类引入的属性初始化
self.height=99.0
对父类引入的属性进行初始化
super.init(age:30)
print("MonkeyMan第二阶段开始")
ifheight <100.0{
self.age=50
}
}
}
varm =MonkeyMan(height:20)
输出结果:
MonkeyMan第一阶段开始
SuperMan第一阶段开始
SuperMan第二阶段开始
MonkeyMan第二阶段开始
重写指定构造方法
子类的构造方法和父类的一模一样
classMan {
varname:String
指定构造方法
init(name:String){
self.name= name
}
}
classSuperMan:Man{
varage:Int
init(){
self.age=30
super.init(name:“lzh")
}
如果子类中的构造器和父类一模一样
必须加上override关键字,表示重写父类方法
在老版本的Swift语言中是不需要override关键字的,新版本才推出的
override init(name:String){
self.age = 30
super.init(name: name)
}
将父类的指定构造器重写成一个便利构造器
也必须加上override关键字,表示重写父类方法
convenienceoverrideinit(name:String){
self.init(name:name)
self.age=30
}
}
varp =SuperMan()
输出结果:
SuperMan init
Man init
便利构造方法不存在重写
classMan {
varname:String
指定构造方法
init(name:String){
print("Man->init")
self.name= name
}
convenienceinit(){
print("Man->convenience init")
self.init(name:"lzh")
}
}
classSuperMan:Man{
varage:Int
init(age:Int){
print("SuperMan->init")
self.age= age
super.init(name:"lzh")
}
Swift中便利构造方法不存在重写,如果加上override关键字
系统会去查找父类中有没有和便利构造方法一样的指定构造方法
有就不报错,没有就报错
为什么便利构造器不能重写呢?
因为便利构造器只能横向代理
只能调用当前类的其它构造方法或指定方法,不可能调用super.所以不存在重写
也就是说子类的便利构造方法不能直接访问父类的便利构造方法,所以不存在重写的概念
convenienceinit(){
print("SuperMan-> convenience init")
self.init(age:30)
}
}
varsm =SuperMan()
输出结果:
SuperMan-> convenience init
SuperMan->init
Man->init
构造方法的自动继承
1.如果子类中没有定义任何构造器,且子类中所有的存储属性都有缺省值,
会继承父类中所有的构造方法(包括便利构造器)
2.如果子类中只是重写了父类中的某些指定构造器
不管子类中的存储属性是否有缺省值,都不会继承父类中的其它构造方法
3.如果子类重写了父类中所有的指定构造器
不管子类中的存储属性是否有缺省值,都会同时继承父类中的所有便利方法
classPerson {
varname:String
varage:Int
init(name:String, age:Int){
print("Person init name age")
self.name= name
self.age= age
}
init(name:String){
print("Person init name")
self.name= name
self.age=0
}
convenienceinit(){
print("Person convenience init")
self.init(name:"lzh")
}
}
classSuperMan:Person{
varheight:Double=175.0
}
如果子类中没有定义任何构造器,
且子类中所有的存储属性都有缺省值,会继承父类中所有的构造方法(包括便利构造器).
父类的存储属性是由父类的构造器初始化,子类的存储属性是由缺省值初始化的.
varp =SuperMan()
如果子类中只是重写了父类中的某些指定构造器
不管子类中的存储属性是否有缺省值,都不会继承父类中的其它构造方法
classSuperMan:Person{
varheight:Double=175.0
init(height:Double){
self.height= height
super.init(name:“lzh", age:30)
}
}
varp =SuperMan()
如果子类重写了父类中所有的指定构造器
不管子类中的存储属性是否有缺省值,都会同时继承父类中的所有便利方法
classSuperMan:Person{
varheight:Double
init(height:Double){
self.height= height
super.init(name:"lzh", age:30)
}
overrideinit(name:String, age:Int){
self.height=175.0
super.init(name: name, age: age)
}
overrideinit(name:String){
self.height=175.0
super.init(name: name)
}
}
必须构造器
只要在构造方法的前面加上一个required关键字
那么所有的子类(后续子类)只要定义了构造方法都必须实现该构造方法
classPerson {
varname:String
早期Swift版本中没有这个语法
requiredinit(name:String){
print("Person init")
self.name= name
}
}
classSuperMan:Person{
varage:Int=30
如果子类没有定义构造器,可以不用重写
init(){
print("SuperMan init")
self.age=30
super.init(name:"lzh")
}
1.如果子类自定义了构造器,就必须重写"必须构造器"
因为如果子类没有自定义任何构造器,默认会继承父类构造器,所以不用重写
2.重写必须构造器不用加override关键字
因为系统看到required关键字就会自动查看父类
为什么重写了还需要加上required关键字,因为所有后续子类都必须重写
requiredinit(name:String) {
print("SuperMan init name")
self.age=30
super.init(name:name)
}
}
varsm =SuperMan(name:"lzh")
输出结果:
SuperMan init name
Person init
析构方法
对象的内存被回收前夕被隐式调用的方法,对应OC的dealloc方法
主要执行一些额外操作,例如释放一些持有资源,关闭文件,断开网络等
classFileHandler{
varfd:Int32?文件描述符
指定构造器
init(path:String){
需要打开的文件路径,打开方式(只读)
open方法是UNIX的方法
letret =open(path,O_RDONLY)
ifret == -1{
fd=nil
}else{
fd= ret
}
print("对象被创建")
}
析构方法
deinit{
关闭文件
ifletofd =fd{
close(ofd)
}
print("对象被销毁")
}
}
varfh:FileHandler? =
FileHandler(path:"/Users/gaoxinqiang/Desktop/lzh.jpg")
当对象没有任何强引用时会被销毁
fh=nil
输出结果:
对象被创建
对象被销毁
析构方法的自动继承
父类的析构方法会被自动调用,不需要子类管理
classPerson {
varname:String
init(name:String){
self.name= name
print("Person init")
}
deinit{
print("Person deinit")
}
}
classSuperMan:Person{
varage:Int
init(age:Int){
self.age= age
super.init(name:"xmg")
print("SuperMan init")
}
deinit{
如果父类的析构方法不会被自动调用,那么我们还需要关心父类
但是如果这样做对子类是比较痛苦的
print("SuperMan deinit")
}
}
varsm:SuperMan? =SuperMan(age:30)
sm=nil
输出结果:
Person init
SuperMan init
SuperMan deinit
Person deinit
Swift内存管理:
管理引用类型的内存,不会管理值类型,值类型不需要管理
内存管理原则:当没有任何强引用指向对象,系统会自动销毁对象
(默认情况下所有的引用都是强引用)
如果做到该原则: ARC
classPerson {
varname:String
init(name:String){
self.name= name
}
deinit{
print("deinit")
}
}
varp:Person? =Person(name:"xmg")
p=nil
输出结果:deinit
weak弱引用
classPerson {
varname:String
init(name:String){
self.name= name
}
deinit{
print("deinit")
}
}
强引用,引用计数+1
varstrongP =Person(name:"xmg")1
varstrongP2 =strongP2
弱引用,引用计数不变
如果利用weak修饰变量,当对象释放后会自动将变量设置为nil
所以利用weak修饰的变量必定是一个可选类型,因为只有可选类型才能设置为nil
weakvarweakP:Person? =Person(name:"xmg")
ifletp =weakP{
print(p)
}else
{
print(weakP)
}
输出结果:
deinit
nil
unowned无主引用,相当于OC unsafe_unretained
unowned和weak的区别:
1.利用unowned修饰的变量,对象释放后不会设置为nil.不安全
利用weak修饰的变量,对象释放后会设置为nil
2.利用unowned修饰的变量,不是可选类型
利用weak修饰的变量,是可选类型
classPerson {
varname:String
init(name:String){
self.name= name
}
deinit{
print("deinit")
}
}
unownedvarweakP:Person=Person(name:"xmg")
循环引用
ARC不是万能的,它可以很好的解决内存问题,但是在某些场合不能很好的解决内存泄露问题
例如两个或多个对象之间的循环引用问题
classPerson {
letname:String姓名
人不一定有公寓
如果这里不加weak的话,当对象设置为nil时,该对象并没有被销毁.
weakvarapartment:Apartment?公寓
init(name:String){
self.name= name
}
deinit{
print("\(self.name) deinit")
}
}
classApartment {
letnumber:Int房间号
vartenant:Person?租客
init(number:Int){
self.number= number
}
deinit{
print("\(self.number) deinit")
}
}
varp:Person? =Person(name:"xmg")
vara:Apartment? =Apartment(number:888)
p!.apartment=a人有一套公寓
a!.tenant=p!公寓中住着一个人
p=nil
a=nil
输出结果:
888 deinit
xmg deinit
classPerson {
letname:String姓名
人不一定有信用卡
varcard:CreditCard?
init(name:String){
self.name= name
}
deinit{
print("\(self.name) deinit")
}
}
classCreditCard{
letnumber:Int
信用卡必须有所属用户
当某一个变量/常量必须有值,一直有值,那么可以使用unowned修饰
unownedletperson:Person
init(number:Int, person:Person){
self.number= number
self.person= person
}
deinit{
print("\(self.number) deinit")
}
}
varp:Person? =Person(name:"xmg")
varcc:CreditCard? =CreditCard(number:8888888, person:p!)
p=nil
cc=nil
输出结果:
xmg deinit
8888888 deinit
可选类型:
可选类型的本质其实就是一个枚举
None没有值
Some有值
格式: Optional<类型>或在类型后面加上?号
由于可选类型在Swift中随处可见,所以系统做了一个语法糖,在类型后面加上?
varopa:Optional
varopb:Int?
varnora:Int
nora=10
print(nora)
print(opb)
输出结果:
10
nil
基本类型变量,在使用之前必须进行初始化,否则报错
目的:安全,不管在什么时候访问都是有意义的
普通变量和可选类型的区别,普通变量只有一种状态,有值
注意:Swift的变量和C/OC的不一样, C/OC可以没有值,是一个随机值
可选类型是安全的么?是,可以通过可选绑定判断后再使用
Swift的发明者完全是基于安全的考虑,当我们使用基本类型时完全不用考虑是否有值
当我们使用可选类型时,总会记得先判断再使用.让程序时刻了解哪些有值哪有没有值
varopb:Int?
opb=55
ifletb =opb{
print(opb!)
print(b)
}
输出结果:
55
55
可选链
通过可选类型的变量来调用相应的属性和方法
可选链的返回值是一个可选值
格式:
可选值?.属性
可选值?.方法
classPerson {
varname:String
init(name:String){
self.name= name
}
funcwhoami() ->String{
print("my name is\(self.name)")
returnname
}
}
varp0 :Person?
varp1 :Person=Person(name:"xmg")
p1.name="zs"
p1.whoami()
输出结果:
my name is zs
如何通过可选类型来调用对应的方法和属性
1.通过强制解包
但是强制解包非常危险,如果可选类型没有值,会引发运行时错误
p0!.name="ls"
p0!.whoami()
2.通过可选绑定,代码繁琐
ifletp =p0{
p.name="ls"
p.whoami()
}
3.通过可选链,如果问号前面的变量没有值,整个可选链会失效
p0=p1
p0?.name="ls"
p0?.whoami()
可选链的返回值会自动包装成一个可选值
因为可选链可用能失效
所以返回值可能有值也可能没有值
要想表达有值或者没有值只能用可选值,所以返回值会自动包装成一个可选值
print(p0?.name)
print(p0?.whoami())
print(p1.name)
vara:String? =p0?.name
p0?.name="ww"
varb:String=p1.name
输出结果:
nil
nil
xmg
可选链调用下标索引
格式:
可选值?[]
structStudent {
varname:String="xmg"
varmath:Double=99.0
varchinese:Double=99.0
varenglish:Double=99.0
要想实现下标访问,必须实现subscript方法
如果想要通过下标访问,必须实现get方法
如果想要通过下表赋值,必须实现set方法
subscript(course:String) ->Double?{
get{
switchcourse{
case"math":
returnmath
case"chinese":
returnchinese
case"english":
returnenglish
default:
returnnil
}
}
set{
switchcourse{
case"math":
因为返回的是可选类型
math= newValue!
case"chinese":
chinese= newValue!
case"english":
english= newValue!
default:
print("not found")
}
}
}
}
varstu:Student? =Student()
可选链调用下标索引不需要.,直接在问号后面写上[]即可
print(stu?["math"])
输出结果:Optional(99.0)
利用可选链赋值.注意:早起版本中不能利用可选链赋值
stu?.name="ww"
print(stu?.name)
输出结果:Optional("ww")
利用可选链给下标赋值
stu?["math"]=88
print(stu?["math"])
输出结果:Optional(88.0)
判断赋值操作是否成功,可选链的赋值操作也有返回值
如果赋值成功会返回一个可选类型
返回()?也就是Viod?代表成功.
返回nil代表失败
letres:Void? =stu?.name="zl"
print(res)
输出结果:Optional(())代表成功.
stu=nil
letres:Void? =stu?.name="zl"
print(res)
输出结果:nil代表失败
多层可选链:
单层:可选值?.属性
多层:可选值?.属性.属性?.属性或者可选值?.属性?.属性?.属性
classA {
varname:String="xmg"
}
classB{
vara1:A?
}
classC{
varb1:B=B()
}
classD{
varc1:C?
}
vara1 =A()
varb1 =B()
varc1 =C()
vard1 =D()
d1.c1=c1
通过d直接给b赋值
由于D中的C是可选值,所以需要在C后面加上?
d1.c1?.b1.a1=a1
通过d直接获取a中的name
其实只需要在可选值后面加上问号即可,如果可选值不存在,那么后面的链失效
print(d1.c1?.b1.a1?.name)
输出结果:Optional("xmg")
标签:
原文地址:http://www.cnblogs.com/lizhiheng/p/5390465.html