Swift之 ? 和 !

2023-11-01

04 June 2014

Swift语言使用var定义变量,但和别的语言不同,Swift里不会自动给变量赋初始值,也就是说变量不会有默认值,所以要求使用变量之前必须要对其初始化。如果在使用变量之前不进行初始化就会报错:

var stringValue : String 
//error: variable 'stringValue' used before being initialized
//let hashValue = stringValue.hashValue
//                            ^
let hashValue = stringValue.hashValue

上面了解到的是普通值,接下来Optional值要上场了。经喵神提醒,Optional其实是个enum,里面有NoneSome两种类型。其实所谓的nil就是Optional.None, 非nil就是Optional.Some, 然后会通过Some(T)包装(wrap)原始值,这也是为什么在使用Optional的时候要拆包(从enum里取出来原始值)的原因, 也是PlayGround会把Optional值显示为类似{Some "hello world"}的原因,这里是enum Optional的定义:

enum Optional<T> : LogicValue, Reflectable {
    case None
    case Some(T)
    init()
    init(_ some: T)

    /// Allow use in a Boolean context.
    func getLogicValue() -> Bool

    /// Haskell's fmap, which was mis-named
    func map<U>(f: (T) -> U) -> U?
    func getMirror() -> Mirror
}

声明为Optional只需要在类型后面紧跟一个?即可。如:

var strValue : String? 

一旦声明为Optional的,如果不显式的赋值就会有个默认值nil。判断一个Optional的值是否有值,可以用if来判断:

if strValue {
    //do sth with strValue
}

然后怎么使用Optional值呢?文档中也有提到说,在使用Optional值的时候需要在具体的操作,比如调用方法、属性、下标索引等前面需要加上一个?,经喵神指正,”Optional Chaining的问号的意思是询问是否响应后面这个方法,和原来的isResponseToSelector有些类似”,如果是nil值,也就是Optional.None,固然不能响应后面的方法,所以就会跳过,如果有值,就是Optional.Some,可能就会拆包(unwrap),然后对拆包后的值执行后面的操作,比如:

let hashValue = strValue?.hashValue 

strValue是Optional的字符串,如果strValue是nil,则hashValue也为nil,如果strValue不为nil,hashValue就是strValue字符串的哈希值

到这里我们看到了?的两种使用场景:
1.声明Optional值变量
2.用在对Optional值操作中,用来判断是否能响应后面的操作

另外,对于Optional值,不能直接进行操作,否则会报错:

//error: 'String?' does not have a member named 'hashValue'
//let hashValue = strValue.hashValue
//                ^        ~~~~~~~~~

let hashValue = strValue.hashValue

上面提到Optional值需要拆包(unwrap)后才能得到原来值,然后才能对其操作,那怎么来拆包呢?拆包提到了几种方法,一种是Optional Binding, 比如:

if let str = strValue {
    let hashValue = str.hashValue
}

还有一种是在具体的操作前添加!符号,好吧,这又是什么诡异的语法?!

直接上例子,strValue是Optional的String:

let hashValue = strValue!.hashValue

这里的!表示“我确定这里的的strValue一定是非nil的,尽情调用吧” ,比如这种情况:

if strValue {
    let hashValue = strValue!.hashValue
}

{}里的strValue一定是非nil的,所以就能直接加上!,强制拆包(unwrap)并执行后面的操作。 当然如果不加判断,strValue不小心为nil的话,就会出错,crash掉。

考虑下这一种情况,我们有一个自定义的MyViewController类,类中有一个属性是myLabel,myLabel是在viewDidLoad中进行初始化。因为是在viewDidLoad中初始化,所以不能直接声明为普通值:var myLabel : UILabel,因为非Optional的变量必须在声明时或者构造器中进行初始化,但我们是想在viewDidLoad中初始化,所以就只能声明为Optional:var myLabel: UILabel?, 虽然我们确定在viewDidLoad中会初始化,并且在ViewController的生命周期内不会置为nil,但是在对myLabel操作时,每次依然要加上!来强制拆包(?也OK),比如:

myLabel!.text = "text"
myLabel!.frame = CGRectMake(0, 0, 10, 10)
...

对于这种类型的值,我们可以直接这么声明:var myLabel: UILabel!, 果然是高(hao)大(fu)上(za)的语法!, 这种是特殊的Optional,称为Implicitly Unwrapped Optionals, 直译就是隐式拆包的Optional,就等于说你每次对这种类型的值操作时,都会自动在操作前补上一个!进行拆包,然后在执行后面的操作,当然如果该值是nil,也一样会报错crash掉。

那么!大概也有两种使用场景
1.强制对Optional值进行拆包(unwrap)
2.声明Implicitly Unwrapped Optionals值,一般用于类中的属性

Swift是门新生的语言,我们有幸见证了它的诞生,激动之余也在佩服苹果大刀阔斧的推出一个新的语言替代一个已经比较成熟语言的魄力,今天在知乎日报上看到一个回答是说Swift是一门玩具语言,正当想去吐槽,发现回答已经被删除了。个人认为苹果是很认真的推出Swift的,从Swift的各种细微的设计也能看的出来。

另外这两个小符号就花费了我不少的时间来理解,可能依然会有错误和不妥之处,欢迎大家指正,本文旨在抛砖引玉。除此之外,Swift还有很多很棒的特性,WWDC 2014 会有四五个和Swift语言相关的Video,大家也可以去关注一下。

最后要感谢喵神的纠正了多处有问题的地方,thx, have fun!

主要参考自苹果的官方文档《The Swift Programming Language》,可以在这里下载到

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Swift之 ? 和 ! 的相关文章

  • 收到 fcm 推送通知时设置应用程序徽章

    我正在使用 FCM 进行云消息传递 当我在后台和前台应用程序状态下收到来自服务器的推送通知时 我想添加应用程序徽章 我缺少什么 主要问题是根据推送通知添加 更新 删除应用程序徽章 我可以接收和处理推送消息 我在这个问题上花了 3 天 请帮帮
  • 为什么 iOS8 中 SKNode 成员的 [NSSet containsObject] 失败?

    两个对象被添加到一个NSSet 但是当我检查会员资格时 我找不到其中之一 下面的测试代码在 iOS 7 中运行良好 但在 iOS 8 中失败 SKNode changingNode SKNode node SKNode unchanging
  • UIWindow.makeKeyAndVisible() 在 XCTest 中抛出“props 必须具有有效的 clientID”错误

    我正在 Xcode 中使用 XCTest 测试 UIViewController 为了测试一些导航和警报功能 我需要将视图控制器放在 UIWindow 中 我使用以下代码执行此操作 let myViewController UIViewCo
  • 检测 UICollectionView 中的页面更改

    我尝试寻找这个问题一段时间 但找不到这个问题的答案 我的问题是我有一个UICollectionView滚动方向是Horizontal with Paging Enabled 我的问题是我想保留用户所在的当前页码 所以我创建了一个int变量
  • 如何在 Swift 项目中导入 Zbar 框架

    我有一个项目 目前正在尝试转换为 Swift 项目 但我不知道如何呈现从相机源进行扫描的 Zbar 条形码阅读器 在我当前的项目中 我这样调用 IBAction scanButton id sender ADD present a barc
  • 从字符串初始化单元

    我正在寻找一个Unit symbol String 一种初始化程序认出 不定义符号 这是一个代码片段 通过提供来说明我的问题有限解 to it 尽管下面的解决方案有效 但明确列出了基础框架如果 Apple 在即将推出的 iOS 更新中发布新
  • 二元运算符“==”不能应用于“UILabel?”类型的操作数和“字符串”

    错误 二元运算符 无法应用于 UILabel 类型的操作数和 字符串 import UIKit class ViewController UIViewController let Soft 5 let Medium 8 let Hard 1
  • iOS 中如何将阴影变成圆形?

    我创建了一个圆形 UIView 它也应该有一个阴影 到目前为止 一切正常 但在角落 阴影没有正确倒圆 如何将阴影角变圆 这是代码和屏幕截图 popupView layer cornerRadius 15 popupView layer sh
  • 方法未到达完成块

    我正在使用SKStoreProductViewController使用以下方法显示 iTunes 产品 该方法被调用 但我没有成功或错误 知道为什么吗 IBAction func BuySomething sender AnyObject
  • 新行命令 (\n) 不适用于 Firebase Firestore 数据库字符串

    我正在使用 Swift 制作一个应用程序 并且正在使用 Firebase Firestore Firestore 是一个数据库 其中有一些我放入的字符串UILabel 对于我的一些字符串 我使用新行命令 或 n 所以我的一些字符串看起来像这
  • UICollectionView 组合布局 - iPad 旋转时项目大小未正确更新

    我有一个目前无法解决的问题 即我正在尝试根据 iPad 位置在集合视图中设置不同数量的列 集合应在设备旋转时更新 目前 取决于设备在开始时的定位方式 第一次旋转项目的宽度未正确计算 iPad屏幕 https i stack imgur co
  • 根据内容调整文本字段的大小

    在用 Swift 编写的 iOS 应用程序中使用自动布局时 如何根据内容调整文本字段的大小 当视图加载以及用户键入时 文本字段将根据需要调整大小以适应其内容 理想情况下 文本字段将在某个点 例如 6 行 停止调整大小 并变得可滚动 你必须使
  • 应用程序在 iPhone 5c 上冻结在主线程上,但在 iPhone 6s 上则不然

    我正在开发一个带有导航控制器的应用程序 Swift 目标 C 重要的提示 在 iPhone 5c 上测试时 这种冻结发生率为 100 而在 iPhone 6s 上测试时则从未发生过 场景是 转到TableViewController A 触
  • 从代码覆盖率中排除 SwiftUI 预览?

    我无法将代码覆盖率提高到最低限度 90 因为 XCode 考虑了 PreviewProvider 我应该怎么办 删除所有 SwiftUI 预览 或者有没有办法可以排除一些带有 PreviewProvider 关键字等的行 Xcode 版本
  • Swift IOS,如何将应用程序用户输入的句子的字母大写,示例;第四个字母和第六个字母?

    用户在文本字段中输入一个句子 然后在一个文本字段中输入数字 4 在另一个文本字段中输入数字 6 它将第 4 个字母和第 6 个字母所在的句子大写 例如 用户输入 一年有 12 个月 输出将是 一年有 12 个月 如何将句子中的第四个和第六个
  • Swift 3 类型推理混乱

    我正在使用 macOS 我有以下代码 1 2 3 4 和 5 之间的唯一区别在于 metrics 参数的内容 let a 20 let met a a 1 This compiles NSLayoutConstraint constrain
  • 在 Swift 4 中,如何删除基于块的 KVO 观察者?

    如果我像这样存储观察者 let observer NSKeyValueObservation foo observe value options new foo change in print change newValue 如何删除 禁用
  • iOS上数组的Swift Metal并行求和计算

    基于 Kametrixomanswer https stackoverflow com questions 38164634 compute sum of array values in parallel with metal swift
  • Swift - 带有两行文本的 UIButton

    我想知道是否可以创建一个包含两行文本的 UIButton 我需要每一行都有不同的字体大小 第一行为 17 点 第二行为 11 点 我尝试过将两个标签放在 UIButton 内 但我无法让它们留在按钮的范围内 我试图在 ui 构建器中完成所有
  • 将 NSTabViewItem 的副本从 NSTabView 添加到同一个 NSTabView

    我正在创建一个简单的网络浏览器 并希望实现选项卡 为此 我使用NSTabView 我基本上希望每个选项卡都有一个WebView这将显示网站已加载 我从只有一个选项卡开始 并希望在创建新选项卡时添加第一个选项卡的精确副本 我尝试过类似的东西t

随机推荐

  • 【华为OD机试c++】最大化控制资源成本【2023 Q1

    华为OD机试 题目列表 2023Q1 点这里 2023华为OD机试 刷题指南 点这里 题目描述 公司创新实验室正在研究如何最小化资源成本 最大化资源利用率 请你设计算法帮他们解决一个任务混部问题 有taskNum项任务 每个任务有开始时间
  • SetFileCompletionNotificationModes FILE_SKIP_COMPLETION_PORT_ON_SUCCESS

    SetFileCompletionNotificationModes function Sets the notification modes for a file handle allowing you to specify how co
  • [git03] 通过pycharm使用git和github的步骤(图文详解)

    一 在Pycharm工具中配置集成Git和GitHub 1 集成Git 打开Pycharm 点击File gt Settins gt Version Control gt Git 然后在 Path to Git executable中选择本
  • Django根据数据库表反向生成models

    1 创建Django项目 创建工程 django admin py startproject movie 创建app python manage py startapp App 在settings py里面添加App INSTALLED A
  • Vue3.0入门 + Vant3.0移动端实践(三)使用Cordova打包Android App

    接着上面两节 把做成的h5小应用打包成android的app放置在手机上看看效果 如何把一个h5应用打包成android的app 使用Cordova就是一种简单不错的办法 当然也有其他的一些办法如使用HBuilderX这一强大的IDE工具
  • VS Code开发常用插件

    VS Code开发常用插件 Chinese Simplified Language 英文菜鸟必备的汉化插件 One Dark Pro个人比较喜欢的一个主题 色调看起来很舒服 Bracket Pair Colerizer加深括号的光标 高亮显
  • Linux服务字符集--locale命令

    在查看Tomcat日志中 会发现中文乱码 乱码的原因就是字符集问题 在 Linux 中 可以使用 locale 命令查看当前系统的字符集 该命令输出当前系统所使用的语言环境信息 包括地域 编码等 执行以下命令 locale 输出结果可能类似
  • 使用Spring Initializer快速创建Spring Boot项目

    默认生成的Spring Boot项目 主程序已经生成好了 resources文件夹中目录结构 static 保存所有的静态资源 templates 保存所有的模板页面 默认不支持JSP页面 可以使用模板引擎 freemarker等 appl
  • github上的文档结构学习

    开源项目目录规范 此为前端开发团队遵循和约定的开源项目目录规范 意在实现开源项目目录结构的一致性 说明 文档中使用的关键字 MUST MUST NOT REQUIRED SHALL SHALL NOT SHOULD SHOULD NOT R
  • RocketMQ发送接收项目实战+对cos或者oss服务上的pdf文件和图片加水印

    使用mq的原因 因为项目中文件上传比较多 需要使用mq分担当前系统线程压力 所以单独使用一个服务来处理文件上传 加快文件上传速度的同时也缓解了当前服务的处理压力 核心服务1 一个项目 发送mq GeneralFileEvent 需要发送给m
  • Qt+gsoap调用WebService

    版权声明 本文为原创作品 请尊重作者的劳动成果 转载必须保持文章完整性 并以超链接形式注明原始作者 tingsking18 和主站点地址 方便其他朋友提问和指正 Qt gsoap调用WebService 1 前言 Qt本身给我们提供了调用W
  • C#系列之ref与out

    目录 1 学习ref与out的原因 2 ref与out的使用 ref的使用 out的使用 3 ref和out的区别 1 学习ref与out的原因 为了解决里面改变外面也改变的问题 使用它们 在函数内部传入的内容里面一旦改变 外面也会跟着改变
  • 连接服务器失败请检查配置文件,连接服务器失败请检查网络

    连接服务器失败请检查网络 内容精选 换一换 当连接目的端服务器失败时 提示 sms 1807 sms 2802 无法连接目的虚拟机 请检查目的虚拟机IP是否可达 或者8899 8900端口是否开放 如下图所示 windows系统迁移时 目的
  • 要做接口并发性能测试,总得先学会分析吧!

    引言 这篇是我3月份在公司内部做的技术分享内容 由于我在公司内部分享的内容较多以及一些特殊性 我摘取了接口并发测试从设计思路整理 测试方案设计 设计分析 代码编写这套流程 我不会承认我把40多页PPT的内容都放在这篇博文里 不管是在内部技术
  • 从零开始制作游戏外挂

    一 什么叫外挂 现在的网络游戏多是基于Internet上客户 服务器模式 服务端程序运行在游戏服务器上 游戏的设计者在其中创造一个庞大的游戏空间 各地的玩 家可以通过运行客户端程序同时登录到游戏中 简单地说 网络游戏实际上就是由游戏开发商提
  • 【专题】我们常用的功能自动化测试工具——Selenium篇

    导语 Selenium也是一个用于Web应用程序测试的工具 Selenium测试直接运行在浏览器中 就像真正的用户在操作一样 支持的浏览器包括IE Mozilla Firefox Mozilla Suite等 这个工具的主要功能包括 测试与
  • 备赛电赛学习硬件篇(二):电源板电路设计

    目录 一 接口 二 稳压部分 三 防反接电路 四 电流与线宽 一 接口 1 输入接口 要准
  • 调试osgEarth(33)分页瓦片卸载器子节点的作用-(3)渲染遍历的帧号和时间设置-TerrainCuller赋值给可渲染图层--TerrainRenderData-Layer

    继续调试 再回顾下Layer类的成员变量 就是说 初始化时调用init 添加到Map上时 setReadOptions gt open gt addedToMap 移除时用removedFromMap 总结下 Layer是个基类 有自己的唯
  • MATLAB实现doc文件的批量改名

    对于一个文件夹中的多个doc文件进行批量改名 下图中是笔者从学生那里收上来的记录表 说了要统一命名也没人听 我又懒得一个个改 只好费点时间编程了 两种实现的思路 一是从旧文件名中选取特定位置的字符 组成新的文件名 要求文件名有固定的位置 比
  • Swift之 ? 和 !

    04 June 2014 Swift语言使用var定义变量 但和别的语言不同 Swift里不会自动给变量赋初始值 也就是说变量不会有默认值 所以要求使用变量之前必须要对其初始化 如果在使用变量之前不进行初始化就会报错 var stringV