Tag: 面向协议

Swift Nifty TableViewCell技巧

像那里的每个Swift开发人员一样,我开始喜欢TableViewCells和面向协议的编程 。 很好,因为今天的技巧结合了两者! 让我们看看在 Swift中注册TableViewCell的常用方法: 首先让我困扰的是容易出错的字符串用法,然后说实话,在99%的时间内 ,单元格标识符只是字符串Cell类名。 也许有些人知道我要去哪里 与Swift中一样,从协议开始: 然后通过实现如下协议使您的单元“ 可重用 ”: 在这里而不是实现它,我们将使用Swift的Protocols Extensions为所有可重用对象提供默认值   ! 默认情况下, reuseIdentifier将是该类的名称! 因此,您现在可以编写: 好的,我们摆脱了容易出错的字符串,但是等一下我们可以做得更好,不是吗? 奖金 辛苦了! 让我们提供一种注册可重用单元格的较短方法 。 再次,救援协议! 在这里,我们说,如果您是注册可重用 TableViewCell的TableView,则默认情况下使用单元格的redirectIdentifier。 现在您可以简单地致电: 恐怕我们要尽力而为🎉🎉🎉 包起来 在这里,我们使用了Swift惊人的协议扩展 ,在TableViewCells的一种非常常见的用法中删除了易于出错的字符串标识符。 我们使代码既简短又清晰,同时使我们不必手工编写所有UITableViewCells复用标识符! 请记住,最好的代码是您不必编写的代码🙂

合理,类型安全且灵活的实现,用于管理Swift App中的错误

上周,我开始重构一些与我现在正在使用的应用程序内的错误管理有关的代码。 我试图在互联网上找到一些实现示例,但是没有运气。 这就是为什么我在这里介绍自己的原因。 错误架构 在大多数情况下,应用程序仅用作前端,以向用户呈现信息。 因此,它与为它提供所需服务和数据的不同实体进行交互。 该实体是例如在线API,本地数据库或第三方框架。 他们所有人都会遇到错误。 我们应用程序的目标是捕获它们并做出相应反应,并在必要时通知用户。 为此,通常将错误与唯一的域ID(通常是字符串)和该域内的唯一代码(通常是整数)相关联,以识别错误。 因此错误架构如下所示: 在大多数情况下,错误还将包含其他关联数据,例如,如果发生错误,您将需要向用户显示本地化描述。 那么,您如何将所有这些信息反映到实现中? 更重要的是,如何使实施易于使用,组织合理,灵活且类型安全? 此外,最好在每个错误域内保修唯一的错误代码,并在编译时在我们的应用程序内保修唯一的域ID 。 一,错误的最低要求 我们可以使用协议指定它们: 我们还可以扩展该协议并添加一些有用的东西: 因为我们将使用具有原始整数值的枚举,所以我们添加了初始化程序和code属性的默认实现。 我们还添加了domain属性,因此我们可以访问错误的域ID,而无需访问其封闭类型(我们在协议中将其声明为静态)。 二,用于存储错误信息的类型 枚举类型是为此目的。 它还允许将原始值链接到每种情况,并保证此原始值是唯一的。 它们是存储错误代码的理想选择。 与ErrorProtocol一起,我们实现了一个基本错误,该错误在编译时为每个域强制使用唯一的错误代码。 域ID不能保证是唯一的(我没有在Swift语言中找到在编译时强制执行的工具)。 三,组织代码 为了组织代码,我选择镜像错误体系结构。 使用嵌套类型,我创建了一个伞形类型,用于存储所有不同的错误枚举(每个枚举与一个错误域匹配): 四,伞型的要求 给定一个域和一个代码,每种包装对应于多个错误域的枚举的伞型都应该能够返回错误。 我们可以通过使伞形类型符合以下协议来获得此功能: 在这种情况下,匹配函数负责探索伞型下每个枚举的域ID,并返回与域和代码匹配的错误。 由于Swift是一种类型安全的语言,因此我们需要为所有包含的枚举指定通用类型。 我们可以通过使用非通用协议作为具体类型来实现。 所有封闭的枚举都应符合此协议以及ErrorProtocol。 真实的例子 让我们看一个真实的例子。 现在,我正在一个名为AVO的应用程序中使用此实现(因此,如果您在即将发布的代码中看到AVO,现在您知道原因了)。 首先,我创建了一个满足我的需求的错误协议,该协议继承自ErrorProtocol并包含错误的本地化描述: 其次,我创建了一个伞形类型来存储所有错误枚举。 我使它符合ErrorUmbrellaProtocol并实现匹配功能: 然后添加错误枚举(在这种情况下为两个域,即内部应用程序错误和服务器错误): 现在我们可以如下使用所有这些。 例如,假设我们从服务器获取域ID和错误代码: 为了检查我们收到的确切错误,(如果您要做的不只是显示本地化的错误说明,还可以通过几种方法来做到这一点: 而且将错误信息发送到应用之外也非常容易: 干净吗? ^^

Swift 4.2中的网络

介绍 好吧,这里通常会花很多时间谈论移动应用程序中网络层的重要性,每个人都知道! 因此,让我们谈谈更重要的事情,如何以可重复使用的方式组织这些事情,而无需一次又一次地重新实现它。 让我们保持简短,着手做生意。 在本教程中,我将分享在POP方法中结合使用可编码的 泛型的经验。 我们将在这里做什么 首先:我们将创建一个请求类型 然后:我们将处理错误类型 下一步:我们将实现一种执行方法并以通用方式映射它 让我们不要忘记整理结果 最后:我们使用请求者类型执行它 请求类型 该对象将封装HTTP调用详细信息: 。 标头 :是HTTP请求和响应的组成部分,通常包含令牌,登录详细信息… 。 参数 :这些是HTTP调用的查询详细信息,将以“ http://……?key = value&key = value”的形式显示 。 BodyParameters:将保存将发送到后端的所有数据。 。 HTTPMethod :GET,POST,PUT … 让我们从编写一些代码开始! 首先,最简单的事情是定义HTTP方法。 现在我们有了方法,我们将为params,header和bodyParams创建typealias。 然后: –我们将创建我们的请求协议 –我们将使用协议扩展为其添加默认行为 –最后,我们创建实现该协议的HTTPRequest结构 繁荣! 而已。 错误类型 这种类型将组织我们层中的错误! 为了更好地处理它。 我们有不同类型的错误: 。 网址错误:网址无效时。 。 数据错误:数据为零时。 。 mappingError:将数据映射到可编码对象失败。 响应错误:当我们在执行请求时收到错误时,我们将为此使用泛型,并在枚举的情况下传递错误值,这是很酷的事情! 让我们开始吧! 一块蛋糕! 错误类型使用通用类型E,以后将是快速错误类型。 结果类型 […]

使用面向协议的编程进行通用JSON解析

澄清 : Codable,本文是关于实现可与Codable或您可能选择的任何东西一起使用的体系结构的 每个(Swift)软件开发人员最终都将需要为其iOS应用程序(或macOS)解析JSON。 在我的整个职业生涯中,我已经看到了许多关于如何解析JSON的体系结构方法。 您应该经常问自己(开发的任何功能): 您构建的体系结构是否是一种演化系统,可以在不修改基础代码/类/结构的情况下适应任何给定的更改( 如果不是,则不敏捷 ) 。 如果您的方法基于OOP,您是否保持SOLID原则不变? 服务是否为松耦合? 在最近的一次聚会中,我也参加了有关体系结构方法和原理的会议,他们展示了一张带有引号的幻灯片: 开发人员知道可以做什么。 应该做的。 那么应该怎么做……? 让我们分解一下JSON解析,即解析JSON涉及的内容: 调用一个请求到服务器并从闭包中获得响应 (例如)。 在大多数项目中,服务器端以不同的合法性响应我们的请求,因此,我们需要一个验证器来验证JSON响应的合法性,而不管我们需要解析的实际数据如何。 4xx我们可以验证JSON,否则,我们将返回错误。 解析 JSON并反序列化相关对象 从验证器 返回相关错误 。 没什么新鲜的,简单明了的🙂 我们的主要目标是编写一个小型且集中的代码,以分离上述所有步骤,并且当然要使用POP方式( 面向协议的编程 )。 我是Alamofire的忠实拥护者,因此我们假设响应是标准的DataResponse : Alamofire.request(…)。responseJSON {(resp:DataResponse )in …} 我们需要一个协议,该协议将描述我们先前细分的方法集。 我们将需要3种方法: 封装运行整个“显示”的实际逻辑的方法。 验证JSON的方法-此方法将返回内部JSON(稍后将显示一个示例)。 一种将解析我们的数据并创建实际对象的方法,该对象应该位于内部JSON内部。 公共协议ParseProtocol { ? ? )-> 吗? 扩展ParseProtocol { ? } 那返回类型呢? 由于方法begin将封装“整个”逻辑,因此它应该返回我们解析的对象以及一个Error类型,然后返回一个元组如何: func begin(forResponse响应:DataResponse […]

练习“在Swift中面向协议编程”的简单代码

这篇文章是使用协议,协议继承,结构和委托针对POP“面向协议的编程”的快速入门。 该样本将为申请大学提供一个简单的过程。 步骤如下: 创建项目后,添加一个名为“ Person.swift”的新文件。 步骤1:创建一个名为Person的协议: 协议人{ var firstName:字符串{获取设置} var lastName:字符串{获取设置} init(fName:String,lName:String) func getFullname()->字符串 } 步骤2:创建从称为“申请人”的人员继承的协议: 协议申请人:{ var email:字符串{获取设置} var grade:浮动{get set} } 步骤3:创建从申请人继承的协议,该协议称为Student: 协议学生:申请人{ var studentId:字符串{获取设置} var dateOfStar:日期{get} } 步骤4:创建一个名为WelcomeMessageDelegate的协议。 此功能将处理视图上显示的结果。 协议WelcomeMessageDelegate { func displayNameDelegate(消息:字符串) } 步骤5:创建注册结构。 除了编写上述函数,我们还需要一个init函数。 Xcode将帮助您编写根据上述步骤定义的所有属性。 结构注册:学生{ init(fName:String,lName:String){ self.firstName = fName self.lastName = lName self.email =“” self.grade = 0.0 self.studentId =“” […]

快速了解所有协议

资源 : 苹果文件 协议定义了适合特定任务或功能的方法,属性和其他要求的蓝图。 然后,该协议可以由类,结构或枚举采用,以提供这些要求的实际实现。 满足协议要求的任何类型都被称为符合该协议。 因此,简单起见,一个协议会说一个struct,class或enum,如果您想成为THAT ,请执行此操作,然后再执行此操作。 例如:如果您想成为人类,则必须饮食,睡眠和休息。 类,结构体,枚举可以通过将协议名称放在类型名称后(用冒号分隔)作为其定义的一部分来采用这些协议。 可以列出多个协议,并用逗号分隔: 如果一个类具有超类,请在其采用的任何协议之前列出超类名称,然后用逗号: swift和Objective-C都支持多级继承。 它只能有一个单一的基类。 两者都不支持多重继承。 如上图所示,仅支持协议的多个继承,以逗号分隔。 您可能已经看到UIViewController的实现UITableview datasource和delegate协议。 class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { } 虽然,最佳实践是将其分组在ViewController的单独扩展中并实现协议。 class ViewController: UIViewController {} extension ViewController: UITableViewDataSource, UITableViewDelegate //implement protocol methods ands variables here.. extension ViewController: UITableViewDataSource, UITableViewDelegate //implement protocol methods ands variables here.. 协议可以具有属性以及符合该协议的类,枚举或结构可以实现的方法。 协议声明仅指定所需的属性名称和类型。 它没有说明该属性是存储的还是计算的。 协议还指定每个属性必须是可获取的还是可获取的和可设置的。 属性要求始终声明为变量属性,并以var关键字为前缀。 […]

iOS中面向协议的Segues

早在2015年,WWDC上就有一个很棒的会议,叫做Swift in Practice。 还有一个示例,说明了如何使用segues面向协议的方式。 因此,我决定将此示例更新为Swift的最新版本,并向您展示。 首先,您应该知道示例应用程序只是一个名为“ Master-Detail”的Xcode模板项目,并进行了一些重构以提高可读性。 完整的源代码可在GitHub上找到。 处理串流的标准方法 当您想使用segues时,通常要做的是重写prepare(for:sender:)方法: 因此,您最终得到了一个不错的segue语法: 结论 这种方法使您的代码更加优雅和类型安全。 另外,如果不处理新的情况,编译器在添加新的序列时也会给出错误。 希望您喜欢本教程。 别忘了拍拍😄。 并在Twitter和Instagram上关注我。

Swift 4:使用可编码协议处理复杂的JSON结构

在任何应用程序中,最常见的功能之一就是解析来自服务器的响应,该响应主要以JSON字符串的形式出现。 虽然在android和其他平台中,有一些库可以用来解析并返回您填充的模型,但与此同时,iOS中缺少此主要功能。 JSONSerializer确实生效了,但是它所能做的就是将您的JSON字符串/数据转换为字典。 因此,您可以自己填充模型,同时要记住类型转换和错误处理。 这不仅增加了代码的大小,而且还花费了很多时间,尤其是在处理庞大而复杂的JSON文件时 解析不带编码的JSON 这是一个看起来很丑的Apple博客,用于在Swift中解析JSON 在Swift中使用JSON – Swift Blog 从创建它的工程师那里获取有关Swift编程语言的最新新闻和有用的提示。 developer.apple.com

Swift:{get}和{get set}之间的区别是,选择哪一个?

自从Apple在2015年WWDC推出面向协议的程序设计以来,可以在互联网上轻松找到很多关于面向协议的程序设计的优点以及如何在日常应用程序开发中使用它的文章。 但是,这些文章中的大多数都忽略了在适应面向协议的编程之前我们需要了解的最基本的知识之一–在声明协议的属性要求时,何时应使用{ get set }和{ get } 。 考虑一下我们有一个符合该协议的协议和一个结构,如下面的代码片段所示。 现在,让我们尝试创建MyStruct的实例并将一些值设置为myVar1和myVar2 。 不出所料,将value设置为myVar1时不会出现任何错误。 但是,即使我们使myVar2仅可获取,我们也能够将值设置为myVar2。 然后出现一个问题:“ { get set }和{ get }什么区别?” 现在,让我们尝试将MyStruct实例MyStruct MyProtocol类型,并将value设置为myVar1和myVar2 。 如您所见,现在尝试将值设置为myVar2时出现错误。 这是什么意思? 这意味着{ get set }和{ get }实际上是在协议级别为我们提供了所需的封装。 当我们在面向协议的编程中使用多态时,这特别有用。 假设您有一个Flyable协议,其中Airplane和Helicopter类均符合该协议。 您还具有SpeedLimitUpdater类,将使用它来更新所有Flyable速度限制。 想象一下,有一天您决定添加一个Bird类,并使它也符合Flyable协议。 等一下……这里有些SpeedLimitUpdater ,这是否意味着我们现在可以使用SpeedLimitUpdater类来更新鸟速限制? 显然,这是不允许的,因为bird不是机器,并且您不能设置它的速度限制。 为了解决这个问题,让我们将Flyable协议的speedLimit只设置为speedLimit ,将Bird类的speedLimit为私有。 SpeedLimitUpdater类的逻辑也需要更新。 如果您有兴趣,可以在这里找到完整的示例代码。 (只需将其粘贴到Xcode游乐场) 从上面的示例中,我们可以看到,在没有充分理由的情况下使用{ get set }将使您的代码更容易出错。 对我们来说, { get }更安全,让符合类型决定属性应具有的访问级别。 这是经验法则 : 在声明协议的属性要求时,请始终使用{get},除非您非常确定要同时设置它和settable。 我希望本文可以帮助您消除在声明协议的属性要求时所遇到的困惑。 […]

协议和扩展…

关键字“协议”用于快速声明协议。 所有类,枚举和结构都可以采用该协议。 协议定义了适合特定任务或功能的方法,属性和其他要求的蓝图。 然后,该协议可以由类,结构或枚举采用,以提供这些要求的实际实现。 满足协议要求的任何类型都被称为符合该协议。 协议在面向协议的编程中被大量使用。 您在协议中声明的所有属性都必须是 { get}或{get set}。 get类型提供了更大的灵活性,我们稍后可以在诸如“ let”或“ var”类型的对象中定义它们。 像OOP一样,我们可以继承/确认另一个协议。 但是在OOP中,我们只能从一个类继承。 也就是说,我们可以有很多子类,但一个类一次只能包含一个父类。 如果您继承一个类,则有时会从父类获取所有API,而有时我们并不需要全部。 在POP(面向协议的编程)中,我们可以一次确认具有多种协议的对象。 这样,我们可以根据需要制定任意数量的协议,然后无论需要什么协议,这些都可以由我们的对象确认。 这提供了很大的灵活性。 合理? 别担心! 我很快会对此做出更多解释! 在以下示例中,我们在集合中使用了两种对象,即类和结构,并将其传递给tableview数据源。 我们可以在函数名称之前使用Mutating关键字,以更改确认对象中的属性(值)。 如果您注意到,在类对象中,我们不需要使用“变异”,因为类对象方法具有预定义的功能来更改其变量。 但是像struct这样的对象是基于值的,因此要更改其属性,我们需要在试图更改其自身对象中的值的函数之前保留“ mutating”关键字。 我们可以在协议中使用初始化程序,以一种简单的方式初始化已确认的对象。 在以下示例中,我们创建了一个对Currency都确认的所有加密货币的集合。 但是集合元素无法访问“货币”协议之外的外部功能或属性。 例如,无法从View Controller中的“ currencies”数组访问CryptoCoin类的“ creatorName ”属性。 我们对现有类型使用“ extension ”关键字,以在POP中添加诸如函数定义和计算属性之类的功能,如果我们在继承对象中需要相同的函数定义(不是全部,而是大多数),该怎么办。 然后我们可以扩展协议,然后在该扩展中定义功能。 然后,无论什么对象需要该功能,都可以确认该协议的那些对象。 如果您愿意,可以在某些子对象中覆盖该func定义。 例子: 我们可以使用扩展将协议一致性添加到现有类型中,您可以在项目中的某些位置定义协议一致性。 我们可以扩展来自(导入的)框架或库的类型。 如果在以上示例中看到,则方形按钮通过确认单个协议来确认两个协议,而该协议本身又被其他两个协议确认。 因此,只有方形按钮才能实现更改背景和文本的两种方法。 其余请根据需要确认协议。 您可以尝试更多以了解更多信息……