常量与变量

常量和变量是某个特定类型的值的名字,如果在程序运行时值不能被修改的是一个常量,反之是一个变量。

一、常量和变量的声明

Swift中的常量和变量在使用前必须先声明。其中let关键字声明常量,var关键字声明变量:

//声明一个名为maximumNumberOfLoginAttempts的整型常量,并且值为10letmaximumNumberOfLoginAttempts=10//声明一个名为currentLoginAttempt的整型变量,并且值为0varcurrentLoginAttempt=0

可以在同一行声明多个变量,中间用逗号,隔开:

varx=0.0,y=0.0,z=0.0

提示
如果在程序运行的时候值不需要发生改变,应该将它们声明为常量,否则声明为变量

变量的值可以进行修改:

varfriendlyWelcome="Hello!"friendlyWelcome="Bonjour!"//friendlyWelcome的值发生改变

常量的值一旦设置后就不能在修改:

letlanguageName="Swift"languageName="Swift++"//编译时出错

类型说明

在Swift中声明常量或者变量可以在后面用冒号:指定它们的数据类型。

//声明一个String类型的变量,可以存放String类型的值varwelcomeMessage:String
提示
实际应用中很少需要指定变量数据类型,Swift会根据所设置的值的类型进行推导。

命名规则

Swift中可以使用任意字符给常量和变量命名,包括Unicode编码,比如中文、Emoji等:

letπ=3.14159let你好="你好世界"letdog="dogcow"

名字里面不能包含数学运算符、箭头、非法的Unicode字符以及不能识别的字符等,并且不能以数字开头。同一个作用域的变量或者常量不能同名。

提示
如果想用关键字作为变量的名字,要用(`)包裹起来。为了方便理解,如果不是万不得已,不应该使用关键字作为变量的名字。

打印变量的值

println函数可以打印常量或者变量的值:

println(friendlyWelcome)//打印出“Bonjour!”

println是一个全局函数,输出时自动在结尾添加换行。print函数与它的功能类似,只是不会在结尾添加换行符。printlnNSLog类似,可以用来输出复杂的日志信息。Swift使用字符串插值来输出变量和常量。

println("ThecurrentvalueoffriendlyWelcomeis\(friendlyWelcome)")//打印“ThecurrentvalueoffriendlyWelcomeisBonjour!”

注释

注释是用来帮助理解和记忆代码功能的,并不会参与编译。Swift有两种注释形式,单行注释和多行注释:

//这是单行注释,用两个斜线开头,直到改行的结尾/*这是多行注释,
可以横跨很多行,
/*比C语言更加NB的是,*/它竟然还支持嵌套的注释!*/

分号

Swift中语句结尾的分号;不是必须的,不过如果想要在同一行中写多个语句,则需要使用;进行分隔。

letcat="cat";println(cat)//打印“cat”

二、属性

属性是依赖于某个特定的类、结构体或者枚举类型的值。Swift有两种属性:存储类型和计算类型。其中存储类型可以作为实例的一部分存放变量或者常量的值,而计算类型的属性值是通过运算的来的。计算类型的属性可以在类、结构体和枚举类型中出现,但存储类型只可能出现在类和结构体类型中。

属性一般依赖于一个特定类型的实例,但是也可以依赖于类本身。依赖于类型本身的属性称为类型属性。

可以定义属性观察者来监督属性值的改变,从而作出响应。

存储属性

常量属性let的值在初始化后不能在改变,而变量属性var的值可以随时更改。

structFixedLengthRange{varfirstValue:Int
letlength:Int
}varrangeOfThreeItems=FixedLengthRange(firstValue:0,length:3)
rangeOfThreeItems.firstValue=6

结构体常量的存储属性

如果一个结构体实例被赋值给一个常量,则这个实例所拥有的存储类型的属性都不能在改变,包括变量属性在内。

letrangeOfFourItems=FixedLengthRange(firstValue:0,length:4)
rangeOfFourItems.firstValue=6//编译错误,firstValue的值不能改变

延时存储属性

延时存储属性的初始值直到第一次使用的时候才进行计算,在声明时通过@lazy进行标记。

提示
一定要将延时存储属性声明为变量(var),因为它的初始值可能会在实例初始化完成后才有,而常量属性一般在实例初始化完成之前就会有值。

当属性的初始值依赖于外部银子,并且该因子的值在实例初始化完成之前不确定时,延时属性非常有用。如果属性初始化时需要进行大量的计算,也可以考虑使用延时属性。

下面是延时属性的示例:

classDataimporter{/*
Dataimporter是一个从外部文件导入数据的类。假设它需要花费较多的时间进行初始化
*/
varfileName="data.txt"
//Dataimporter类的数据导入功能}

classDataManager{
@lazyvarimporter=Dataimporter()vardata=String[]()//DataManager类提供数据管理功能}

letmanager=DataManager()
manager.data+="Somedata"manager.data+="Somemoredata"//Dataimporter实例还没有创建

只有访问DataManagerimporter属性时才会去创建这个对象。

println(manager.importer.filename)//创建importer属性并打印“data.txt"

存储属性与实例变量

Objective-C类的对象可以使用属性或者实例变量来存储值。Swift中并没有所谓的实例变量,而是将它们统一为属性了,这样使得属性的声明更加简化。

计算属性

除了存储属性外,类、结构体和枚举类型还可以定义计算属性。这些计算属性并不能够存储值,而是通过getter方法和可选的setter方法来间接的获取和设置其它属性和值。

structPoint{varx=0.0,y=0.0}structSize{varwidth=0.0,height=0.0}structrect{varorigin=Point()varsize=Size()varcenter:Point{
get{
letcenterX=origin.x+(size.width/2)
letcenterY=origin.y+(size.height/2)returnPoint(x:centerX,y:centerY)
}

set(newCenter){
origin.x=newCenter.x-(size.width/2)
origin.y=newCenter.y-(size.height/2)
}
}
}varsquare=Rect(origin:Point(x:0.0,y:0.0),size:Size(width:10.0,height:10.0))
letinitialSquareCenter=square.center
square.center=Point(x:15.0,y:15.0)println("square.originisNowat(\(square.origin.x),\(square.origin.y))")//打印”square.originisNowat(10.0,10.0)“

这个例子定义了三个结构体来表示几何形状:

  • Point封装了(x,y)坐标。

  • Size封装了宽度和高度。

  • Rect用坐标原点和大小定义一个矩形。

其中Rect结构体还提供了一个center的计算属性。这个属性的值是由矩形的originsize属性决定的,它本身并不需要存储信息。但是改变center的值,会间接的修改矩形的其它属性。

computedProperties_2x

三、简化setter的声明

如果没有为计算属性的setter的新值指定名字,则默认使用newValue。下面是Rect结构体的另外一种写法:

structAlternativeRect{varorigin=Point()varsize=Size()varcenter:Point{
get{
letcenterX=origin.x+(size.width/2)
letcenterY=origin.y+(size.height/2)returnPoint(x:centerX,y:centerY)
}
set{
origin.x=newValue.x-(size.width/2)
origin.y=newValue.y-(size.height/2)
}
}
}

只读的计算属性

如果一个计算属性只有getter而没有声明setter,则它是一个只读的计算属性。只读属性只能通过点语法返回一个值,而不能对它进行设置。

提示
必须使用var声明计算属性,包括只读的计算属性在内,因为它们的值是可能改变的。而let只能用于常量的声明,表示它们的值不能发生改变。

还可以省略只读计算属性声明中的get关键字。

structCuboid{varwidth=0.0,height=0.0,depth=0.0
varvolume:Double{returnwidth*height*depth
}
}

letfourByFiveByTwo=Cuboid(width:4.0,height:5.0,depth:2.0)println("thevolumeoffourByFiveByTwois\(fourByFiveByTwo.volume)")//打印“thevolumeoffourByFiveByTwois40.0”

属性观察者

属性观察者用来观察和响应属性值的变化。每次设置属性的值都会调用相应的观察者,哪怕是设置相同的值。

可以给除延时存储属性以外的任何存储属性添加观察者。通过重写属性,可以在子类中给父类的属性(包括存储属性和计算属性)添加观察者。

提示
不需要给类本身定义的计算属性添加观察者,完全可以在计算属性的setter中完成对值的观察。

通过下面两个方法对属性进行观察:

    willSet在属性的值发生改变之前调用。
  • didSet在设置完属性的值后调用。

如果没有给willSet指定参数的话,编译器默认提供一个newValue做为参数。同样,在didSet中如果没有提供参数的话,默认为oldValue

提示
willSetdidSet观察者在属性进行初始化的时候不会被调用。
classstepCounter{vartotalSteps:Int=0{
willSet(newTotalSteps){println("AbouttosettotalStepsto\(newTotalSteps)")
}
didSet{iftotalSteps>oldValue{println("Added\(totalSteps-oldValue)steps")
}
}
}
}

letstepCounter=StepCounter()
stepCounter.totalSteps=200//AbouttosettotalStepsto200//Added200stepsstepCounter.totalSteps=360//AbouttosettotalStepsto360//Added160stepsstepCounter.totalSteps=896//AbouttosettotalStepsto896//Added536steps
提示
如果在didSet中给属性设置新值,最终结果就是最后设置的这个值。

全局变量与局部变量

上面关于计算属性和属性观察对全局变量和局部变量同样成立。全局变量定义在任意的方法、函数、闭包或者类型定义之外。而局部变量则定义在方法、函数或闭包之内。

之前遇到的全局变量或者局部变量都跟存储属性类型,都是用来存储值的。但实际上它们也能像计算属性有计算变量。

提示
全局变量和常量与延时属性类似,总是延时进行计算。但是它们并不需要使用@lazy标记。
局部常量和变量一定不是延时计算的。

类型属性

实例属性属于某个特定类型的实例。每次创建的实例,它都拥有自己的一组独立的属性值,不受其它实例对象影响。

你还可以定义属于类型本身的属性。这些属性是与具体的实例无关的,不管创建多少个实例都只有一份。这种属性称之为类型属性

可以给值类型(结构体和枚举类型)定义存储和计算类型的类属性,但是只能给类定义计算类型的类属性。值类型的存储属性可以是变量或常量。

提示
一定要给存储类型的类属性设置初始值。

类型属性语法

在C/Objective-C中只能使用全局静态变量来定义依赖与某个属性的变量或常量。但是在Swift中可以直接将它们定义为类型的一部分。其中结构体和枚举类型中使用static关键字,而在类类型中则使用class关键字。

structSomeStructure{
staticvarstoredTypeProperty="Somevalue."
staticvarcomputedTypeProperty:Int{//returnanIntvaluehere
}
}

enumSomeEnumeration{
staticvarstoredTypeProperty="Somevalue."
staticvarcomputedTypeProperty:Int{//returnanIntvaluehere
}
}

classSomeClass{
classvarcomputedTypeProperty:Int{//returnanIntvaluehere
}
}
提示
上面的计算属性都是只读的,但实际上可以定义为可读可写

使用类型属性

类型属性通过类型名字和点操作符进行访问和设置,而不是通过实例对象:

println(SomeClass.computedTypeProperty)//print"42"println(SomeStructure.storedTypeProperty)//prints"Somevalue"SomeStructure.storedTypeProperty="Anothervalue."println(SomeStructure.storedTypeProperty)//prints"Anothervalue."

下面演示了如何使用一个结构体来对声道音量进行建模,其中每个声道音量范围为0-10。

staticPropertiesVUMeter_2x

structAudioChannel{
staticletthresholdLevel=10
staticvarmaxInputLevelForAllChannel=0
varcurrentLevel:Int=0{
didSet{ifcurrentLevel>AudioChannel.thresholdLevel{
currentLevel=AudioChannel.thresholdLevel
}ifcurrentLevel>AudioChannel.maxInputLevelForAllChannels{
AudioChannel.maxInputLevelForAllChannels=currentLevel
}
}
}varleftChannel=AudioChannel()varrightChannel=AudioChannel()

leftChannel.currentLevel=7println(leftChannel.currentLevel)//prints"7"println(AudioChannel.maxInputLevelForAllChannels)//prints"7"

当修改其中一个声道的值时,整个声道的音量最大值就可能发生改变。而每个声道都有自己的当前音量水平。

Swift编程高级教程 变量与常量的更多相关文章

  1. HTML5 3D书本翻页动画的实现示例

    这是一款十分炫酷的HTML5 3D书本翻页动画,效果相对比较简单,拖拽鼠标模拟用手翻页,需要的朋友们下面随着小编来一起学习学习吧

  2. 使用postMessage让 iframe自适应高度的方法示例

    这篇文章主要介绍了使用postMessage让 iframe自适应高度的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  3. ios – UIPopoverController出现在错误的位置

    所以我花了一些时间寻找答案,但到目前为止还没有找到任何答案.我正在尝试从UIInputAccessoryView上的按钮呈现弹出窗口.UIBarButtonItem我想显示popover来自定制视图,所以我可以使用图像.我创建这样的按钮:当需要显示popover时,我这样做:但我得到的是:弹出窗口看起来很好,但它应该出现在第一个按钮上时出现在第二个按钮上.然后我发现了这个问题:UIBarButto

  4. ios – 如何从变量访问属性或方法?

    是否可以使用变量作为Swift中方法或属性的名称来访问方法或属性?在PHP中,您可以使用$object->{$variable}.例如编辑:这是我正在使用的实际代码:解决方法你可以做到,但不能使用“纯粹的”Swift.Swift的重点是防止这种危险的动态属性访问.你必须使用Cocoa的Key-ValueCoding功能:非常方便,它完全穿过你要穿过的字符串到属性名称的桥,但要注意:这里是龙.

  5. iOS >>块>>更改块外部的变量值

    我不是在处理一个Object并改变它,就像我的mString一样.我希望’center’属性的行为类似于myInt,因为它是直接访问的C结构,而不是指向对象的指针.我希望’backgroundColor’的行为类似于我的imstring,因为它是一个指向一个新对象的对象的指针,不是吗?

  6. ios – Xcode Bot:如何在post触发器脚本上获得.ipa路径?

    我正在使用机器人来存档iOS应用程序,我需要获取.ipa产品路径才能将其发布到我们的分发系统中.机器人设置:并使用脚本打印所有env变量,其中不包含ipa文件的路径.此外,一些变量指向不存在的目录,即:XCS_OUTPUT_DIR这里的env变量输出:除此之外,我还能够确认.ipa文件是在另一个文件夹中创建的(/IntegrationAssets//

  7. ios – 使用附加字符串本地化Info.plist变量

    我正在尝试本地化应用程序的名称,同时仍然能够根据构建配置追加字符串.所以目前它被设置为:该设置定义为:通过这种方式,我们可以为应用程序添加后缀以用于不同的beta版本.问题是,当我们尝试本地化本地化的InfoPlist.strings中的应用程序显示名称时,就像这样我们覆盖存储在Info.plist中的值,并丢失后缀字符.这有什么好办法吗?

  8. iOS – 开始iOS教程 – 变量之前的下划线?

    这是正确的还是我做错了什么?

  9. ios – 静态计算变量被多次实例化

    我有一个日期格式化程序,我试图在UITableViewCell子类中创建一个单例,所以我创建了一个这样的计算属性:问题是我不止一次看到print语句,这意味着它不止一次被创建.我已经找到了其他方法,但我很想知道这里发生了什么.有任何想法吗?解决方法您的代码段相当于只获取属性,基本上它与以下内容相同:如果你只想运行一次,你应该像定义一个惰性属性一样定义它:

  10. ios – UIApplication.delegate必须仅在主线程中使用[复制]

    我应该在主调度中的viewControllers中声明这些)变量位置声明定义了它的范围.您需要确定这些变量的范围.您可以将它们声明为项目或应用程序级别(全局),类级别或特定此功能级别.如果要在其他ViewControllers中使用这些变量,则使用公共/开放/内部访问控制将其声明为全局或类级别.

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部