在上一篇文章中,我们讨论了Closures的语法以及如何在其接收函数中使用它们。 今天,我们通过确保视图尽可能与控制器分离,来研究一种可用于在应用程序中实施分离和可扩展性的技术。 什么是代表? 委托模式被认为是解决关注点分离的一种可能解决方案,即任何对象都应处理自己的独特问题集。 例如,矩形结构不应处理计算圆的面积,依此类推。 这是一个非常明显的例子,但是委托的思想是一个对象应该使用专门的帮助对象来完成一项任务。 在MVC中,视图应负责向用户显示内容。 由于用户将通过单击,点击或按下视图来与视图进行交互,因此它们还必须接收输入事件。 但是,控制器的责任是实际解释输入并决定采取什么措施来响应输入,这是我们需要真正考虑设计的地方。 那么,如何在不使其中一个过于依赖另一个实现的情况下将视图的输入传递给控制器? 我们可以认为Controller在这方面是代表吗? 让我们从代码开始 让我们看一下我们将用于实验的类。 这是我们的BaseController,当我们要扩展应用程序时,它指定了一些不错的功能: 协议控制器{ 关联类型ViewType var typedView:ViewType {get} } class BaseViewController :UIViewController,控制器{ 覆盖func loadView(){ self.view = ViewType() } var typedView:ViewType { 如果让view = self.view为? ViewType { 返回视图 }其他{ 让view = ViewType() self.view =视图 返回视图 } } } 这是我们的BaseView,它为我们的View执行相同类型的操作: BaseView类:UIView { 便利init(){ self.init(frame:.zero) } 覆盖init(frame:CGRect){ […]
尽管每篇文章都以其实现和用法解释了NSNotifications,但很少有人对它的基础知识给予足够的重视。 在这里,我试图突出显示遗漏的这些点。 使用NotificationCenter,您可以将数据从应用程序的一部分广播到另一部分。 它使用“ 观察者”模式 ,通过称为“ 通知中心”的中央调度程序,在收到通知时通知注册的观察者。 NotificationCenter 究竟 如何 工作? 它基本上有三个组成部分 侦听通知的“侦听器”,称为观察者 “发件人”,在发生某些情况时发送通知 通知中心本身,可跟踪观察者和通知 NSNotificationCenter可以处理一对多和多对多通信。 您何时使用 NotificationCenter ? 当应用程序的两个或多个没有正式连接的组件之间进行通信时, 当沟通需要反复一致地进行时 使用一对多或多对多通讯时 您如何注册观察员? NotificationCenter.default.addObserver(自身,选择器:#selector(onDidReceiveData(_ :)),名称:.didReceiveData,对象:无) addObserver(_:selector:name:object:)函数具有4个参数: 第一个参数observer是未命名的 ,您可以为其提供对作为该通知观察者的对象的引用,该对象通常是self 第二个参数selector是在发生通知时要调用的函数,其作用类似于目标动作模式 第三个参数name是您要侦听的通知的名称,其类型为Notification.Name 第四个参数object是一个可选对象,您希望接收其通知,因此,如果设置了该对象,则只会从该“发送者”接收通知 您如何添加通知? 扩展Notification.Name { 静态let didReceiveData = Notification.Name(“ didReceiveData”)静态let didCompleteTask = Notification.Name(“ didCompleteTask”)静态letcompleteLengthyDownload = Notification.Name(“ completedLengthyDownload”) } NotificationCenter.default.addObserver(自身,选择器:[selector],名称:.didCompleteTask,对象:nil) 您如何发布通知? NotificationCenter.default.postNotification(名称:.didReceiveData,对象:无) onDidReceiveData(_:)函数如下所示: @objc func onDidReceiveData(_通知:通知) {如果让数据= […]
现在已经有一段时间了,我们一直在从事银行iOS应用程序项目。 我们一直在使用用Objective-C编写的Forms的旧框架,因此我们开始研究更新和更灵活的替代方案。 我们发现Eureka很好地解决了我们的问题,但我们还需要创建许多自定义元素。 在本文中,我将通过概述如何发现Eureka以及如何编写自定义元素来分享我们的经验。 在此表单框架的帮助下,我们可以做什么? 尤里卡(Eureka)的最大力量在于框架已经包含的许多行中。 您可以直接使用它们,选择范围非常广泛。 仅举几例: TextRow , DateRow , CheckRow ,各种格式的数字行,列表行等。 Eureka存储库的自述文件中的图片也可以说明一切。 基本的构建块是节 , 行和单元 。 它们有助于从逻辑上构建表单并抽象出UITableView的复杂性,而Eureka显然是基于此构建的。 这些构建块使您可以专注于表单本身,而不是UITableViewDataSource和Delegate的实现细节。 这些部分等效于UITableView部分。 它们将表单元素的逻辑部分归为一个共同的标题。 它们在可选部分中具有特殊含义,我们将在后面介绍。 行可以解释为表单的元素,其中包含项的值和语义。 它们可以保存类型安全值 ,可以被禁用或隐藏 。 它们也可以具有定义的自定义属性。 单元格是行表示的实现。 他们拥有用户界面。 Eureka框架定义了许多单元,但是您可以定义自己的单元。 单元格对行属性的变化做出反应。 每个行都有其对应的Cell ,它已通过泛型定义了其类型。 泛型实际上是框架的重要组成部分。 如果您查看源代码,则可以看到它们。 对于我们最基本的示例,我们将实现一个简单的表单,其中包含名称,生日和一个布尔值(如果有人喜欢Eureka)。 我们还将使用一个按钮行,它将预填充前3个字段。 这听起来很简单-实际上确实如此,但是为我们提供了编写Eureka Forms的良好介绍。 为了更好地了解这一点,我制作了我们正在构建的应用程序的屏幕截图。 构建第一部分的最基本代码如下: 输入选择器允许用户通过显示出现在键盘区域中的选择器来选择答案。 如果要使用Eureka提供的默认单元格,则代码很简单。 视图控制器中的代码非常简单,因此我将向您展示而无需任何进一步的说明。 我们定义了我们在这里使用的自定义StringLengthRow类。 我将更详细地介绍这些自定义元素的定义代码。 我们定义两个类。 对于行,我们使用StringLengthRow,对于单元格StringLengthCell。 让我们从StringLengthRow开始,因为这是更简单的一种,并且将在我们的viewcontroller代码中使用。 在这里,我们只声明要设置的属性。 我们还在初始化程序中定义了如何获取新单元格。 我们选择从笔尖加载它。 StringLengthCell当然更复杂。 […]
曾几何时,王国中有一个很棒的App。 该应用程序非常复杂,并包含许多晦涩难懂的部分,但它给使用它的所有用户带来了极大的欢乐。 但是,有一天,一个邪恶的错误出现了,并向王国的App用户显示了一个难看且难以理解的错误代码。 一位勇敢的开发人员被要求杀死龙来修复该错误,并且得到的票差不多是这样的: “用户无法继续购买-有时会出现一个奇怪的错误,有时什么也没有发生。” 勇敢的开发者拿起他的键盘,然后…忽略了该错误,删除了整个代码库,并重新编写了Swift 5中的所有内容。 再也没有看到错误代码,从此以后他们都过着幸福的生活。 结束。 不幸的是,现实生活中没有这样的童话。 存在错误,作为开发人员,您的任务是了解问题并加以解决。 现在,让我们看一下最常见的问题和iOS应用程序中通常如何处理错误的不足之处。 当应用失败并没有任何反应时,这可能意味着某个时刻丢失了一个或多个错误。 例如: 虽然这种方法的一些负面结果可能看起来很明显,但其他一些则更加模棱两可。 显而易见的是:用户屏幕上出现难看且难以理解的错误消息 这些错误消息显然不是针对用户的。 这些对用户可见的唯一结果是在App Store中有许多不良评论。 模棱两可:重要信息的丢失 相同的低级(网络/解析/核心数据)错误可能会以多种不同方式影响您的应用。 如果仅传播原始错误,则介于两者之间的所有信息都将丢失,不被记录或跟踪,最终调试该错误将变得更加困难。 对于用户而言,这些不希望的结果以及代码的完整性可以并且应该避免。 或者,如何以标准且一致的方式传播错误。 错误管理始终是任何应用程序的重要组成部分,甚至更重要的是,如果您的应用程序分为内部Pod,开发Pod,开放源Pod,库,实用程序和内部框架。 在整篇文章中,我们将这些依赖项称为“ 模块 ”。 在Just Eat,我们探索了Swift / Objective-C代码库的几种选择。 最后,我们选择继续使用经典的常绿NSError和NSUnderlyingErrorKey Universe,这是一种特别在macOS中使用的方法,自平台诞生之初就由Apple提出。 在介绍建议的解决方案之前,让我们先介绍几个关键概念。 如官方文档和NSHipster在本文中所述,NSError对象由以下内容组成: 错误域 -表示“错误上下文”或错误来源的字符串。 错误代码 -表示错误的Int值。 错误创建者有责任使其有意义。 不同的域可以具有完全不同的含义的相同错误代码。 用户信息字典 -包含有关错误的所有其他有用信息的字典。 错误链是NSError的链接列表。 每个错误都使用标准键NSUnderlyingErrorKey将先前的错误嵌入到用户信息字典中。 您可以将其视为标准链接列表。 如下所示。 我们汇总了一组准则,以统一我们在所有应用程序的各个部分,模块和库中进行错误管理的方法。 最终结果是一个一致的代码库 传播 展示架 日志 应用中生成的任何错误。 这意味着从应用程序用户界面收到的最终错误结构如下所示: […]
Swift世界演变:SE-0185合成可量化和可哈希化的一致性Swift正在发展。 Swift 4即将出现,Swift 5开始。 我开始这个新系列,继续关注它的发展。 这不是详细的建议的简单解释。 SE-0185刚刚被接受。 因此,让我们开始吧。 SE-0185是关于Equatable和Hashable的。 我已经发布了一系列解释Equatable,Comparable和Hashable的文章,如下所示。 迅捷世界:平等,可比和可哈希化的第1部分 迅捷世界:平等,可比和可哈希化的第二部分 迅捷世界:平等,可比和可哈希化的第三部分 简而言之,SE-0185建议通过编译器自动合成代码,使其符合Equatable和Hashable,而不是由开发人员手动合成。 我们将从具有两个属性的简单Struct超级英雄开始:name和real name。 要使用==进行相等性测试,需要遵循Equatable,如以下代码片段所示。 假设超级英雄的名字和真实名字相等时是相等的。 一个明显的不足是,类型中属性的任何更改都会导致Equatable一致性的更改。 通过手动更新将增加维护成本和潜在风险。 如果我们将出生日期或年龄添加到超级英雄怎么办? 我们需要相应地更新此一致性。 在相同的情况下,可散列尤其是需要高质量的散列函数以实现一致性。 该提案中的解决方案是 如果类型的所有成员都是Equatable / Hashable,则该类型综合符合Equatable / Hashable的一致性。 例如,在我们的超级英雄中,由于name和realName均为String,因此Equatable的一致性由编译器合成。 如果我们给出自己的实现,它将被我们的实现所取代。 现实世界更加复杂。 该提案描述了不同类型和不同条件的详细信息。 请从SE-0185和线程swift-evolution通用等效性,哈希性和可比性中获取详细信息。 该建议成真后,我们会回来。 谢谢你的时间。 请拍手让更多的人看到此文章。 请点击关注,关注我和Swift World 。 强烈欢迎本周《 Swift World》的建议。
有时需要实现一种算法,用于对Swift项目中的字符串,文件或其他数据进行加密/解密。 不幸的是,这种类型的算法从其他语言(例如Java)到Swift的转换并不简单。 Unicode标量 在幕后,Swift的本机String类型是根据Unicode标量值构建的。 Unicode标量是字符或修饰符的唯一21位数字,例如用于U+1F425 LATIN SMALL LETTER A ( “a” )的U+0061或用于前”🐥” ( “🐥” )的U+1F425 在Swift中,可以从UnicodeScalar值构造一个UnicodeScalar 。 我们可以从Int构造一个UnicodeScalar 。 这允许许多转换。 使用utf8和utf16这两个属性都可以访问String所有Int值。 使用这些属性,我们可以将基于数字的转换应用于字符。 注意: 将String转换为byte array和short array 让字符串:字符串=“ abcd” let byteArray:[UInt8] = string.utf8.map {UInt8($ 0)} let shortArray:[UInt16] = string.utf16.map {UInt16($ 0)} //还有另一个带有更多编码的方法如果让数据:Data = string.data(使用:.windowsCP1252,allowLossyConversion:true){//现在,您可以简单地循环遍历datafor i中的字节,即0。.<data.count {data [i] / / UInt8 value} //或者,如果您仍需要UInt8 arraylet byteArrayFromData:[UInt8] = [UInt8](data)} […]
第4部分:使用AppAuth在iOS上设置OAuth2授权 关于使用ORY Hydra,Vapor和iOS设置OAuth2的系列教程的这一部分将重点介绍构建iOS客户端。 如果用户成功登录,它将是一个非常简单的应用程序,仅显示一个用于创建帐户的按钮并切换到成功消息。我们将使用一个名为AppAuth的库与我们的授权服务器进行交互。 教程系列 第1部分:ORY Hydra授权服务器的介绍和设置 第2部分:Vapor后端中的用户管理 第3部分:将Vapor后端设置为ORY Hydra的身份提供者 第4部分:使用AppAuth在iOS上设置OAuth2授权(您在此处) 先决条件 您应该检出上面列出的系列的先前部分。 创建iOS Xcode项目 打开Xcode或您选择的编辑器,然后创建一个新的Single View应用程序。 已经为您提供了ViewController.swift类,其视图已在情节提要中配置。 打开情节ViewController ,然后在ViewController上添加一个按钮,以触发身份验证流程。 然后添加带有成功消息的隐藏标签,在用户成功登录后,我们可以显示该标签。 接下来,打开ViewController.swift文件,并拖动其中两个按钮的插座,以及一个按钮操作的插座。 调用该函数authorize 。 另外,我们需要允许该应用处理非SSL URL。 为此,我们需要在Info.plist添加另一个名为App Transport Security Settings条目: 触发授权请求 创建授权请求后,我们现在需要实际触发该请求。 我们可以使用AppAuth提供的便利功能来创建一个新的OIDExternalUserAgentSession ,并将其保存在AuthService 。 将此行添加到我们的AuthService的顶部: 在AuthService.swift中保留当前的身份验证流 然后修改authorize看起来像这样: AuthService.swift中的授权功能 首先,我们将函数的签名更改为采用UIViewController以及成功和错误情况的回调。 然后,通过使用之前创建的请求创建新的授权会话来触发授权请求。 创建授权会话后,我们将收到OIDAuthState对象或错误。 OIDAuthState是OIDAuthState提供的便利类,其中包含有关用户授权状态的所有相关信息。 返回到ViewController并在点击创建帐户按钮时调用此函数。 在ViewController.swift中授权功能 我们创建了AuthService的实例,并在按钮点击时调用authorize 。 如果我们可以成功授权用户,则显示成功消息而不是按钮。 iOS部分就是这样。 测试我们的设置 现在,我们开发了实现OAuth2授权所需的所有三个部分。 为了能够对其进行测试,我们需要启动Hydra服务器,运行后端并运行iOS客户端。 启动Hydra Server:回顾第1部分,并按照以下步骤启动Hydra Server并创建客户端 […]
到2019年,Swift已从Apple的少数几个开源项目之一发展成为一种功能强大的语言,成为Apple系统开发背后的强大力量,甚至还扩展到了Linux等其他操作系统。 现在处于4.2版中,期待已久的Swift 5发行版,Swift因其协议定位和为多个平台编写本机应用程序的能力而变得非常流行。 Swift 3是所有Swift用户和开发人员的标志性版本:它是代码破解版本,更改了大多数语法,删除了语言方面并添加了其他内容,并引入了其他主要工具和增强功能,例如Swift Package Manager和Swift Linux的核心库。 但是,随着Swift 3的到来,对开发人员来说,另一个艰难的决定。 Swift软件包管理器(Swift Package Manager)是Swift开发人员的第三个软件包管理器,但也是第一个正式软件包管理器,现已投入使用,使库和框架的选择和分发过程更加多样化。 Swift的包装管理困境 Google的词典将困境定义为“必须在两个或多个替代方案之间做出艰难选择的情况,尤其是同样令人讨厌的替代方案。”现在,我不会说所有可用的软件包管理器都是令人讨厌的,但我可以同意,它们都不是完美的。 与任何软件一样,程序包管理器都有其成功之处和不足之处,尽管每种缺点在开发中使用时都可能导致麻烦。 Swift的三个主要包管理器是Cocoapods,Carthage和Swift包管理器(SPM)。 Cocoapods是该小组中的老大,自从Objective-C是Apple的主要软件开发语言以来就一直存在。 Cocoapods最初于2011年9月17日发布,最初是为使用面向对象的C风格语言的库和框架提供服务的,为随之而来的软件包管理者铺平了道路。 当Swift成为主流时,Cocoapods慷慨地扩展到包括新语言的库和框架,新语言是其他程序包管理器将在以后建立的语言。 当2014年11月到来时,下一个软件包管理器发布了,这意味着Cocoapods不再是使用Xcode的那些的唯一发行商。 多种选择的能力都很强,这使得最初的Swift软件包管理器引起了争议。 尽管许多人认为它对Swift和Objective-C开发人员来说是革命性的,但其他人却因为它的明显缺点对其进行了轰炸。 Cocoapod最显着的功能之一就是它完全自动化了依赖程序,开发人员只需运行pod install ,Cocoapods便会获取并构建依赖项,将其插入项目中,将其链接到项目中,并生成一个包含两者的工作区。项目和豆荚。 事实证明,虽然该功能是主要的便利,但开发人员并不完全满意:尽管该过程确实节省了他们大量的时间和精力,但它也将对项目的控制权移交给了Cocoapods并让其处理文件和项目设置。 开发人员感到这是一种无声的痛苦,直到下一个程序包管理器发布时,这种痛苦才得以表达。 随着时间的流逝,开发人员对允许流行的第三方掌控为其项目构建程序包的满意度越来越低。 尽管较新的软件包管理器是用Swift编写的,但对于Swift而言,Cocoapods是用Ruby编写的,这意味着开发人员确实需要熟悉该语言才能操作软件包管理器。 许多人确实知道Ruby,而且学习曲线并不复杂,因此添加另一种语言的文件带来的不便并不麻烦。 但是,Swift的软件包管理器不是用自己的语言(例如Nuget,PyPi或NPM)编写的,而不得不使用另一种语言的事实给开发人员带来了痛苦。 Cocoapods是集中式的,这在软件包管理器中很常见(一个常见的指标是软件包注册表)。 程序包管理器中的集中化意味着存在一个中央代码注册表,可以在其中托管和查看程序包,并且客户端(通常是命令行界面)可以从中提取代码以生成程序包。 可以从cocoapods.org上浏览其网络上托管的所有Pod,这对于那些没有特定软件包或只想浏览可用软件包的开发人员来说非常有用。 但是,许多人似乎对新的分散化概念感到迷惑,这意味着Cocoapods不再是理想的包裹管理系统。 尽管Cocoapods有其缺点,并且最近一直受到嘲笑,但是它仍然是Swift的包管理器中最古老的,并且由于其自动化,对初学者非常友好。 CocoaPods.org iOS和Mac项目的依赖管理器 cocoapods.org 迦太基是第二位进入该小组的包装经理,从一开始它就与Cocoapods的主要区别显而易见。 它于2014年11月18日发布,在Swift 1.1正式发布后仅两个月就可用,并且支持Swift中的Objective-C。 迦太基在Cocoapods中发现了一个对开发人员来说很酸的话题:虽然Cocoapods是用Ruby编写的,但是Carthage完全用Swift编写了一个包管理器来迎合用户。 除了以Apple支持的语言以及您的项目被编写时,依赖管理的强大功能之外,Carthage还声称它利用Xcode的构建系统,同时为开发人员提供了集成其依赖的自由。 通过迦太基,开发人员可以控制他们项目的依赖关系,从而使他们能够在迦太基构建之后,根据自己的选择进行链接和管理。 第一次学习如何将Carthage集成到您的项目中(以及随后针对更复杂的需求)时,Carthage的README具有令人难以置信的描述性和实用性,但是对于经验较少的开发人员来说,开始使用它可能非常复杂。 但是,随着集成过程的延长,从长远来看,它将带来更多的简化和控制。 设置好迦太基并链接了依赖项后,只需要将一行添加到一个非常简单的文件(而不是将一行或多行添加到Ruby文件)和一个命令, carthage update ,就可以生成新的框架。可以导入原始文件的方式。 迦太基消除了在较大的.xcworkspace中处理多个.xcproject文件的麻烦,并消除了与核心项目一起添加的庞大文件结构,而仅在项目根目录中使用.framework文件夹对项目进行了补充,该文件夹清楚地说明了名称。框架。 迦太基提供了Swift,Objective-C或其他语言的其他软件包管理器所没有的某种程度的控制,那就是完全控制。 刚开始创建运行脚本并将框架链接到项目似乎很困难,但是一旦习惯后,该过程将变得异常顺利。 […]
这是关于如何将OpenStreetMap地图视图导出到ARKit的3d模型中的超短教程。 我将尝试使其尽可能简单和快捷地🙂 从https://developer.apple.com/arkit/下载ARKitExample 打开http://www.openstreetmap.org/并导出您感兴趣的区域,如下图所示(请原谅我的波兰语)。 输出文件将具有.osm格式(http://wiki.openstreetmap.org/wiki/OSM_XML)。 值得注意的是,所选区域不能太大(我试图使用几平方公里的区域,并且Blender和iPhone都存在渲染纹理问题,但我会尽力弄清楚并更新本文)。 3.下载OSM2World Java应用程序,该应用程序将.osm文件转换为.obj模型和.obj.mtl纹理文件(http://osm2world.org/download/)。 打开先前导出的.osm文件并导出到.obj 4.下载Blender(https://www.blender.org/download/)并打开.obj文件(obj.mtl将自动导入,不用担心)。 值得一提的是,您可以从模型中移除灯光,因为在SceneKit中添加和管理灯光更加容易。 接下来只是导出(文件->导出)模型,选择Collada格式(.dae),这是SceneKit首选的格式。 5.用新创建的.dae文件替换ARKitExample中的一种模型,然后使用它。 如有任何问题,请随时在Twitter https://twitter.com/tbaranowicz上ping我
将Web嵌入本机应用程序是一种将应用程序快速添加内容的常用方法。 它不仅可以提供支持访问,联系表格,还可以提供用于引导缺少功能的更复杂方法。 Webkit框架允许您将其与Javascript结合使用,以改善用户体验。 从历史上看,iOS允许使用将Web嵌入到UIWebView中。 作为第一种方法,它很方便,它自己处理cookie,但在JavaScript方面却非常有限,主要是因为缺少核心引擎。 Webkit出现了,该框架允许开发人员使用相同的Javascript引擎在其移动应用程序中为Safari提供动力。 为了使用某些Javascript内容测试我们的iOS应用,我将使用一个HTML文件,其中包含非常基本的形式和两个javascript函数:*登录操作,将数据形式转发到本机应用*一种更改标题的方法这页纸 它可能看起来像下面的人 function sendLoginAction() { try { webkit.messageHandlers.loginAction.postMessage( document.getElementById(“email”).value + ” ” + document.getElementById(“password”).value ); } catch(err) { console.log(‘The native context does not exist yet’); } } function mobileHeader() { document.querySelector(‘h1’).innerHTML = “WKWebView Mobile”; } WKWebView可以使用自定义配置进行初始化,包括使用的用户代理,Web视图要使用的数据存储以及用户内容控制器,以最终与Web视图本身关联。 这是我们用来从iOS向Java脚本发送呼叫的方法。 首先,我们需要创建此用户内容控制器并创建我们要处理的用户脚本。 let contentController = WKUserContentController() let userScript = WKUserScript( source: “mobileHeader()”, injectionTime: […]