Tag: swift

为什么编码很重要:位和字节入门

那是编码的黑暗时代。 交流很容易中断,普通用户很难弄清楚到底出了什么问题。 此问题是由于使用不同的编码来读取字节序列而导致的。 要了解此问题的症结,我们来看两个关键术语: 位 :信息的基本单位,通常表示为0或1 字节 :固定长度的位序列,通常由8位组成 因此,一个字节将被表示为2⁸= 256个数字,范围从0到255(或以位为00000000到11111111)。 字节中的位被赋予索引。 最右边的位(也称为最低有效位 )的索引为0,最左边的位(也称为最高有效位 )的索引为7。 今天,情况仍然如此,顺便说一句! 至少可以说,使用二进制(或十六进制)表示法麻烦且效率低下。 需要某种编码标准。 这就是奇怪的地方,因为您可能已经猜到,原始位序列的含义根据所使用的编码而改变。 输入ASCII码 ASCII是一种字符编码标准,它使用7位表示基于英文字母的128个指定字符。 0到32之间的数字保留给控制字符,这些控制字符指示如何解释和表示数据。 它们被设计用于打印控制,数据结构和传输控制。 所有未重音的英文字符都使用32到127之间的数字。 这里的关键是ASCII是为不重音的英语字符设计的。 尽管该编码仅使用7位(不使用整个位),但是ASCII不能轻松地用于许多其他语言。 例如,亚洲字母有成千上万个字母,这些字母再也不会适合8位。 许多其他字母都使用重音,例如ˆ ´ , ¨等。 因此,就像美国开发ASCII ,其他国家也创建了自己的编码。 这导致了基于不同语言的需求和细微差别以及需要进行转码的各种代码标准的不一致混合。 实质上,不同的国家/地区具有不同的编码标准。 当计算机问世时,就不可能在为不同标准量身定制的软件之间有效地交换信息。 然后是ISO/IEC 8859 —一种与8位 ASCII向后兼容的编码,由来自拉丁文字的191个字符组成。 它包含各种口音 ,可以完全覆盖南非语,科西嘉语,法罗语,挪威语和许多其他内容。 但是, ISO/IEC 8859仅使用单字节固定长度编码对前256个Unicode字符进行编码,这意味着某些语言仍然不兼容。 例如,考虑为西里尔字母设计的ISO/IEC 8859–5 : 以及GB 18030中华人民共和国的官方字符集: 尽管西里尔字母已集成在ISO/IEC 8859 ,但它不支持中文书写系统。 输入Unicode Unicode是一种计算行业标准,用于对世界上大多数书写系统中表示的文本进行一致的编码,表示和处理。 最新版本的Unicode(9.0)包含超过128,000个字符的库,涵盖135个现代和历史性脚本以及多个符号集。 […]

Swift:字符串和路径

TL; DR: StringsAndPaths.playground 我看到多次弹出的一小段代码来自StackOverflow上的答案,该答案不能被否决。 此摘要是不推荐使用NSString上的方法且Swift无法使用的方法的结果。 该方法是stringByAppendingPathComponent ,虽然添加路径组件是很常见的方法,但新String类不再是一个选项。 要获得此功能应该怎么做? 一种解决方案可能是将字符串和路径字符简单地连接在一起,但是这样做会导致错误。 原因是不同的环境使用不同的字符作为路径分隔符。 例如,在Mac和Linux上,它是“ / ”,而在Windows上,它是“ \ ”。 我选择解决此问题的方法是访问GitHub上的Swift存储库并搜索此方法,然后我很快找到了它。 该功能在Swift中存在,但标记为不可用,并带有注释,说明应改用URL类。 每当我想找到我在Objective-C中反复使用过的方法时(我在Swift中找不到),我都会回到GitHub以相同的方式进行搜索。 现在,我们对如何进行这项工作有了一个提示。 除了使用NSString之外 ,还可以创建URL实例,并可以使用函数appendingPathComponent 。 不利的一面可能是有必要创建一个对象的新实例,这使得转换为NSString具有吸引力。 但是,当URL类已经做到这一点时, 字符串不应该负责处理路径的逻辑。 迁移到Swift的一个重要原因是对Unicode字符集的改进支持。 回到NSString放弃了所有的改进。 最好找到在纯Swift中前进的新方法。 GitHub Gist

独立导航栏

声明导航栏的独立性 大多数情况下,我们使用UINavigationBar附带的UINavigationBar 。 在这种情况下,导航控制器将创建强大的条形图并将其显示,并且我们可以随时使用导航控制器对象访问实际的条形实例。 导航控制器还将自己设置为关联导航栏的委托。 但是,如何管理所有这些导航内容呢? 实际上,它具有相当合理的机制。 UINavigationBar包含用于显示内容的UINavigationItem数组。 根据Apple文件,UINavigationItem 手段; 当关联的视图控制器可见时,将由导航栏显示的项目。 例如,每当您将视图控制器推入导航控制器堆栈时,导航控制器都会获取即将到来的视图控制器的导航项,并将其推入导航栏的导航项数组。 另外,如果您从导航堆栈中弹出当前视图控制器,其导航项也会从导航栏的导航项数组中弹出。 如果要在其上方显示的导航栏上进行更改,则应处理视图控制器的导航项。 从Apple文档中获取的数据可以使您更清楚地了解这些内容。 当然,由于有了导航控制器,所有这些东西大多数时候都会在后台自动运行。 实际上,为了澄清谁可以控制上述导航栏,如果您问谁是导航栏的主角,答案肯定是UINavigationController 。 但是 ,可能有时候我们想打破这种纽带。 您可以认为它是没有必要的,甚至您可能也认为应该避免使用它,因为它是默认行为。 但是,让我们看一下我在现实世界中遇到的问题的简化版本; 您可以看到使用交互式弹出手势时导航栏正在褪色。 实际上,我认为它看起来很酷,但是这可能是不受欢迎的行为,尤其是您的产品经理期望您从屏幕顶部到底部的可靠过渡。 在这种情况下,我们应该使用独立的导航栏。

通过创造混乱来进行单元测试竞赛条件(快速)

多线程竞争条件不会始终如一地发生,这使得它们很难重现。 另一方面,最佳软件实践要求我们编写自动化测试以验证我们的更改。 我将分享我的技术来创建足够的混乱,以使那些罕见的崩溃变得足够可靠以进行测试。 什么是比赛条件? 如果您有多个线程试图同时变异和访问数据,可能会发生不好的事情。 一个线程可能会更改一个值,而另一个线程正在使用它! 避免这种情况的最好方法是以不可能的方式构造代码。 Swift的结构是一个很好的起点,因为它们是在写操作时复制的(额外的功劳:从功能上考虑!)。 但是我们不能总是做理想的事情。 我们在现实世界中发展,但我们的控制范围之外。 也许我们陷入了遗留代码库。 也许我们没有时间或金钱来重构所有东西。 有时,我们所能做的就是实施最佳实践。 最佳实践之一是: 修复错误时,编写一个可重现该错误的单元测试以防止退化。 通常这是直截了当的,但是这些竞争条件崩溃可能很棘手。 它们很少出现在崩溃报告器中,并且您从未在设备上看到过这种情况。 让我们崩溃 首先,设置一个包含一些不安全代码的简单方法: 不料? 更像预期的那样。 现在,您可以修复它,并且可以放心,将来的更改不会使它恢复正常。 肖恩每天在 Livefront对抗 混乱 。

在Swift中从文档目录中保存和获取图像?

每个应用程序在文档目录中都有其自己的存储。 在文档目录中,用户可以存储音频,视频,图像,pdf和其他文件,而不会与其他应用冲突。 您还可以读写Document目录中特定应用程序的数据。 文档目录将用户数据或文件存储在应用程序路径中。 所有文件都存储在特定应用程序的文件夹中。 您可以从文档目录的路径读取应用程序数据。 将图像保存在文档目录中: func saveImageDocumentDirectory(){ 让fileManager = NSFileManager.defaultManager() 让路径=(NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask,true)[0] as NSString).stringByAppendingPathComponent(“ apple.jpg”) let image = UIImage(名称:“ apple.jpg”) 打印(路径) 让imageData = UIImageJPEGRepresentation(image !, 0.5)fileManager.createFileAtPath(路径为String,内容:imageData,属性:nil) } 获取文档目录路径: func getDirectoryPath()->字符串{ 让路径= NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask,true) 让documentsDirectory = path [0]返回documentsory } 从文档目录获取图像: func getImage(){ 让fileManager = NSFileManager.defaultManager() 让imagePAth =(self.getDirectoryPath()as NSString).stringByAppendingPathComponent(“ apple.jpg”) 如果fileManager.fileExistsAtPath(imagePAth){ self.imageView.image = UIImage(contentsOfFile:imagePAth) }其他{ 打印(“无图像”) } […]

Swift已经具有结果类型

也许。 在过去的几年中,我有幸使用多种语言编写和部署应用程序。 Scala,ruby,javascript,haskell,clojure等。每次我拿起一个工具时,特别是如果它对我来说是新的,我都会尝试学习它的精髓。 编程语言是任何人都可以用来构建事物的思想和概念的工具箱。 但是,我对同事和在线使用当前可用工具的不满之处感到非常不满。 Rob Napier谈论了快速不是功能语言的话题,您应该注意一下。 这是关于如何使用一种语言的方式,而不是人们希望的方式的一课。 但是,我真的很失望Rob提出swift应该添加一个Result枚举。 Swift已经具有此功能,但是我想很多人都不喜欢它。 Swift具有Optional类型,但通常不会直接看到它。 您通过语言构造与可选元素进行交互。 一个例子: 在上面的示例中找不到“可选”,“一些”和“无”的字样。 Optional基本上是一种“也许”类型,直接在其语言中获得支持真的很好。 无需编写一堆case .some和其他类似的语句,我们只需使用let和其他语言结构来检测其中是否有任何东西。 下面的示例类似于针对Result类型看到的许多示例: 乍一看,这似乎很好。 我在许多快速项目中都添加了这样的枚举。 但是,最近我注意到,我总是不得不执行大量的仪式来从枚举中提取值: 或者可以尝试仅提取并使用成功案例: 为了与语言中已经存在的工具作斗争,需要进行大量工作。 Swift已经可以将函数标记为返回两种类型之一,一种是成功,另一种是Error ,并且它是throws 。 现在,我们可以使用语言的内置功能来调用该函数: 我已经说过很多人说他们避免throws因为他们认为使用异常进行控制流是不好的。 我同意,大多数情况下例外对于控制流是不合理的。 throw不会引发异常。 从迅速的文档: Swift为运行时引发,捕获,传播和操作可恢复错误提供了一流的支持。 错误不是例外情况。 可恢复的错误是预期的,应该对此进行计划。 标记为throws的函数返回Error类型为失败的结果,并且编译器强制程序员处理成功和错误情况。 do和catch就像专门的switch和case关键字,用于函数何时返回成功或错误值并提供人们期望的模式匹配功能。 是的,有rethrows以在函数堆栈中传播错误。 我在scala中做了完全相同的事情,以便在诸如Web请求之类的过程中“顺流”处理Result的错误。 这是使用类型和模式匹配的控制流,我很高兴它已内置在语言中,而不必每次都自己构建。 “ try ”一词是解释我要完成的任务的完美方法: 尝试一下,如果无法解决,我将以其他方式处理。 尝试/捕获情况的开始不是我最喜欢的单词,但我想不到更好的方法了。 我不是敏捷专家,我每天都不会使用它,我想听听您对这个问题的看法。 还是应该迅速添加一个Result枚举,并让程序员在throws和Result之间进行选择? 还是某些片段库会一直枚举而其他枚举却全部枚举的碎片库? 谢谢阅读。

第四天:什么是快速落败?

如果要转到 第3天的 上一篇文章 ,或者要从 第1天 开始 。 有趣的故事 :我在一家知名公司的采访中,他们进行了第一轮的客观类型问题,有四个选择。 一个特别的问题(或您可以说的选项)引起了我的注意,该问题是基于开关控制流的问题,它有一个选项是失败。 我认为这是打印错误,在Swift中没有一个名为fallthrough的关键字。 面试刚结束,我就意识到自己是多么的傻瓜。 重新营业! 如果您使用C风格的语言进行过任何编程,则将特别记住开关控制流程中的一个非常不安全的功能,即如果我们不(或偶然地错过了,我经常这样做)在案例结束后写断点 ,那只会在接下来的情况下驳船? (谁给我一些隐私,bru?) 显然, Swift是更安全的语言,它的默认特性不是那样,而是更简洁 , 可预测,并且避免错误地执行多个切换案例 。 但… 如果您想在Swift中使用(C样式)功能,则需要在每次 您需要的情况。 Swift编程语言书中的示例 失败 最后一件事,也是最重要的 fallthrough关键字不检查导致执行陷入的switch条件的条件。 fallthrough关键字仅导致代码执行直接移至下一个case(或default case)块内的语句,就像C的标准switch语句行为一样。 那是一个问题,明天见。 如果您在本文中❤️,请给我一个give,并支持我的工作。 等等,要继续吗? 转到第5天 。 没有人会知道!

消息传递在Objective-C中如何工作–刘关山–中等

消息传递在Objective-C中的工作方式 调用Objective-C方法时,该方法将转换为objc_msgSend函数。 objc_msgSend是objc / message.h文件中定义的C函数。 第一个参数是接收的Objective-C对象本身,第二个参数是选择器,其余参数是传递给Objective-C方法的参数。 该过程称为消息传递。 objc_msgSend函数确定在运行时如何处理到接收对象的消息。 大致是objc_msgSend函数的工作方式: 如果接收对象为nil,则将消息重定向到nil接收器(如果有)。 默认行为是什么也不做。 检查类的缓存。 如果实现已被缓存,请调用它。 将选择器与类中定义的选择器进行比较。 如果找到匹配项,则调用匹配的实现。 否则,请检查其超类,直到没有超类为止。 呼叫+ resolveInstanceMethod: / + resolveClassMethod : 。 如果返回“是”,则表示选择器将解决这个问题。 因此,请转到步骤2并重新开始。 在这里,您可以调用class_addMethod来动态提供给定选择器的实现。 致电-forwardingTargetForSelector:。 如果返回非零,则将消息发送到返回的对象。 请注意, 此处返回自身将导致无限循环。 调用– methodSignatureForSelector : 。 如果返回非nil,则创建一个NSInvocation实例,并将其传递给-forwardInvocation:。 找不到指定选择器的实现。 它将在接收对象上调用– didNotRecognizeSelector:。 默认实现会引发异常。

卸下电池样板

斯威夫特3.0 在iOS中,单元与可重复使用性的标识符相关联。 一个主要的难题是跟踪哪个小区标识符应该与哪个小区相关联。 借助协议的强大功能,开发人员不再需要手动创建这些标识符。 我们可以在内部将类名用作单元格标识符,并且可以通过包装程序处理所有此类。 一个可命名的协议将解决这个问题。 可命名 协议可命名{ 静态var名称:字符串{get} } 扩展名为{ 静态变量名称:字符串{ 返回字符串(描述:自我) } } 扩展UIView:可命名的{} 请注意,所有UIView都可以访问NameProtocol。 现在,我们可以使用类的名称作为单元格标识符。 碰巧的是,UICollectionViewCell继承了UICollectionReusableView的子类,而UICollectionReusableView继承了UIView的子类。 另外,UITableViewCell子类为UIView。 因此,我们的单元已经可以命名了! 寄存器 现在,我们可以使用类名直接在代码中注册单元格。 为了帮助删除更多样板,请将以下方法添加到UITableView扩展中。 func register(cells:[UITableViewCell.Type]){ cells.forEach { registerClass($0, forCellReuseIdentifier : $0.name) : $0.name) } } 现在,我们可以以简洁的格式优雅地整齐地注册我们的单元格。 您不再需要跟踪那些令人讨厌的标识符! 出队 现在已经注意了寄存器部分,让我们看一下出队。 将以下方法添加到您的UITableView扩展。 func dequeueReusableCell (对于indexPath:IndexPath)-> T { 返回dequeueReusableCell(withIdentifier:T.name,for:indexPath)为! Ť } 这将使用正确的标识符使单元出队。 同样,此包装器将返回适当的UITableViewCell子类。 行动中 在ViewControllers的viewDidLoad中,您可以注册单元格。 tableView.register([firstTableViewCell.self]) 在cellForRowAtIndexPath中,可以使用出队包装器。 […]

使用Swift的ARKit测量长度

您是否曾经历过需要测量设备的经历,但现在没有任何东西了? 不要害怕! 因为,实际上我们可以使用ARKit使用我们的iOS设备来测量从一个点到另一个点的对象。 在此应用程序中,我们将添加两个点,这些点将确定测量的开始和结束。 同样,长度为英寸的文本将显示在端点的正上方。 为了获得更好的参考,您可能还希望在此处查看整个代码库。 设定 首先,我们需要创建一个增强现实应用程序。 对于这种情况,我们将其命名为ARRuler。 选择Swift作为其语言,选择内容技术作为SceneKit 。 我们无法为此选中单元测试和UI测试 ,因为我们不会使用它。 在我们的viewDidLoad()方法中,我们也可以删除以下行,因为我们不需要它们。 sceneView.showsStatistics = true 让场景= SCNScene(名称:“ art.scnassets / ship.scn”)! sceneView.scene =场景 另外,在相同的viewDidLoad()方法中,让我们添加sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints],以便我们可以跟踪ARKit将使用的设备位置。 添加起点和终点 现在我们的项目已经设置好,让我们使用以下代码覆盖touchesBegan(_:with) ,以检测触摸是否在视图中发生。 覆盖func touchesBegan(_ touches:Set ,事件:UIEvent?){ } 接下来,我们需要在ARSCNView中获取第一次触摸的位置。 然后使用触摸位置执行命中测试,以查看它是否对应于特征点。 由于命中测试结果返回一个数组,因此我们将使用第一个数组添加一个点。 如果让touchLocation = touches.first?.location(in:sceneView){ 让hitTestResults = sceneView.hitTest(touchLocation,类型:.featurePoint) 如果让hitResult = hitTestResults.first { addDot(at:hitResult) } } 正如您所注意到的,我们还没有创建addDot(at 🙂方法。 此方法应接受ARHitTestResult 。 […]