Tag: 继承

Swift类:基础知识

描述:类与结构非常相似,但是在决定使用哪种结构时要知道有重要的区别。 使它们与众不同的是,类可以从其他类继承,具有反初始化器并允许对一个类实例的多个引用。 结构不能做这些事情。 声明一个类与使用结构完全一样,但是从关键字class开始。 属性:类,因为结构可以具有存储的属性或计算的属性。 存储的属性可以具有观察者,计算的属性可以具有setter和getter(请参见Swift计算属性)。 如果为所有属性提供默认值,则似乎不需要使用初始化程序。 在这种情况下,我们正是这样做的。 初始化程序即将推出,然后我们将删除默认值。 方法:与类关联的函数是否与结构相同。 但是,与结构不同,如果要更新类中的属性值,则无需为方法使用关键字mutating。 初始化器:类没有默认的初始化器(结构具有默认的初始化器),这意味着您需要创建自己的初始化器,以便所有属性都具有值。 如下所示,即使已分配了默认值,初始化器也将为类的属性分配值。 继承定义了一种关系,在该关系中可以根据超类定义子类。 继承是类和结构之间的主要区别。 子类继承了超类的所有功能(属性,方法,下标),并可以通过点语法对其进行访问。 如下所示,我创建了子类InheritanceExample ,该子类继承了BudgetTest的所有功能。 无需在子类中设置任何功能,就可以使用超类的初始化程序创建InheritanceExample的实例, 我可以通过点语法访问超类功能。 子类也可以放置其自身的功能 在下面的代码中, printDescription和ownFeature特定于此类。 您还可以注意到使用了super.init,它调用了超类的初始化程序。 初始化子类的过程如下:首先初始化子类的属性,然后调用超类的初始化程序以将值设置为其自身的属性。 覆盖方法,属性和下标:我们使用关键字override来指示子类将根据您要更改的内容来更改属性,方法或下标。 Override要求编译器验证超类是否具有可以被覆盖的匹配声明,如果不存在匹配则抛出错误。 如果在某些示例中遇到了关键字super ,请知道它用于访问超类的功能。 请参阅以下示例: 在上面的代码中,我重写了一个方法,并通过使用super关键字调用了该方法的超类实现。 这使我可以扩展该超类的方法,因为可以为其添加新功能。 防止超越? 在变量,方法之前使用关键字final

Swift 4.2可降解:异构集合📚

继去年发布Codable协议之后,许多iOS开发人员一直在忙于删除沉重的自定义JSON解析器,并在模型层中将它们替换为对Decodable的流畅且轻量级的构造……我也不例外:在最近的项目中作为一个客户,我很高兴增强大型应用程序的模型层,其目标之一就是完全符合Codable。 挑战1:嵌套的异构集合 最初,过渡到Decodable的过程很顺利(“祝您删除代码愉快!” )。 但是,自定义JSON解析器的删除导致重要的类类型映射的删除-原本功能强大的Codable协议未直接支持Codable 。 为了举例说明我在说什么,请考虑以下几点: 在这种非常简单的情况下,我们有一个超类Pet,它被两个类Cat和Dog继承,从而允许一个人拥有一个超类Pet的单个集合,而集合中的实际对象是Pet, Cat or Dog类型。 从JSON解码Person对象时会发生问题,因为“宠物”列表中的对象不是同一类型: 宠物列表将在Person初始化程序中像这样解码: container.decode([Pet].self, forKey: .pets) ,但这样做将检索超类Pet对象的列表,从而失去所有子类属性。 用Cat或Dog代替Pet也是不够的,因为我们对每种不同的类型(包括它们各自的属性)都感兴趣。 同时使用JSONSerialization反序列化JSON以使用类型区分JSONSerialization进行映射,似乎完全消除了使用Codable的好处,因为这是使用旧JSON解析器完成的方式。 解决方案:集中类映射 幸运的是,我并不孤单地遇到这个问题:Tom Stoffer写了一篇很棒的文章,介绍如何处理嵌套在Decodable对象中的异构列表。 尽管此解决方案在某种情况下是好的,但对于大型项目而言,这并不是一个非常干净的解决方案,因为我们可能会重复类型映射代码,因此我们可能会遇到多个对象相同的异构列表。 为了解决这个问题,我们可以将类型信息(映射)提取到类家族的集中位置。 这可以通过利用快速枚举上的函数来完成。 目标是通过公开用于检索正确映射的类型的函数以及JSON有效内容中类型鉴别符的键,来创建一个表示相关类家族的枚举。 因为我们希望解决方案尽可能通用,所以我们可以编写一个协议来定义所需的公开信息: 注意:仅在您为鉴别器使用不同键的情况下,才真正需要鉴别器类型。 (在我正在从事的项目中,我有两个不同的键)。 此外,鉴别变量是静态的-稍后会详细介绍。 ClassFamily协议允许我们创建一个描述任何对象族的枚举。 让我们看一个例子,说明我们的Pet案例的枚举是什么样的: 太好了,这个枚举现在描述了我们的宠物对象家族! 然后,我们可以直接在Person类的可解码的初始化程序中使用它,如下所示: 但老实说,此解决方案仅提取了映射,并没有真正使初始化程序更简洁。 因此,为了解决这个问题,我们将在KeyedDecodingContainer:的扩展中创建解码函数的泛型重载KeyedDecodingContainer: 这样做可以使我们极大地清理Person的初始化程序: 我们已经完成了可解码对象的嵌套异类列表的解决方案-干净整洁,不是吗? 但这不是全部… 挑战2.异构集合作为返回类型 …如果异构集合未嵌套在Decodable对象中怎么办? 例如,考虑以下情况: Person的Pets集合不是属性,而是在运行时通过API调用从服务器获取的: 在这种情况下,问题仍然存在: [Pet]类型的解码将导致带有名称的未知宠物的列表。 使用Cat或Dog也是不够的,并且为了像Tom Stoffer的方法一样,我们不像在Person类的初始化程序中那样具有带键控容器的Decoder对象。 令我惊讶的是,我在Stackoverflow或其他地方找不到很多类似情况的信息,然后返回反序列化JSON以读取鉴别符类型,然后进行解码,这对我来说是不可接受的。 解决方案:包装器类! 因此,经过数小时的类型推断问题和编译错误,我设法使用包装器类和一些枚举提出了一个通用解决方案。 这个想法是能够通过利用相同的类家族枚举来使用与嵌套集合相同的方法。 为此,我们必须围绕可解码类(及其子类)创建一个包装器类,然后可以将其映射到正确的类型。 让我们看一下如何实现它。 包装器必须是可解码的,以便我们使用JSONDecoder直接对其进行解码。 此外,它需要保留对我们希望创建的对象的引用。 […]

协议-Swift的力量

更新于2019年2月24日,格林尼治标准时间上午4:51 5:30+ 先决条件—任何Swifty iDev均可初学者或专家阅读。 通过从头到尾阅读本系列文章,初学者将获得知识,专家将增强其知识。 我们都知道Apple的UIKit,MapKit和所有其他框架都是在委托模式的基础上开发的。 大多数iDev都知道协议是用于委托人和数据源在视图,视图控制器或自定义类之间传递和请求数据的,但是该协议的真正功能是类型转换 ,AnyObject是迅速实现的协议,用于存储任何类型的对象。 类型转换是将变量或值的数据类型从一种类型转换为另一种类型的过程。 我还有一个问题,如果上面是类型转换,那么协议在这里的作用是什么? 当然,经过几个动作,我会给这个问题一个答案,敬请期待。 让我们首先介绍基本概念。 以上只是原始类型转换的一个简单示例。 原始类型转换是由Int,Float,Double等编程语言提供的原始数据类型之间的类型转换。 另一种类型转换是类级别的类型转换,有时称为自定义类型转换。 类,结构,枚举被视为可以由像您这样的开发人员创建的自定义类型,自定义类型转换在继承中起关键作用。 — — — — — — — — — — — — — — 该类的每个实例都有#n个类类型 — — — — — — — — — — — — — — 如果A类不是任何类的子类,则#n将为A类 [例如(A类)— A没有任何超类] — — — — — — — […]

用继承编写可测试和可维护的代码

总览 软件工程师应努力实现的众多目标之一是构建可测试且可维护的代码,并且似乎许多人无法编写此类代码。 我敢肯定有很多原因会导致这一因素,例如完成项目的紧迫期限,或者工程师可能没有学习编写代码的正确方法。 我在Kaodim工作,我很高兴能有机会向我的前辈学习,并能够理解为什么我们倾向于以某种方式做事。 我记得在Kaodim编码我的第一个功能时,我在很多方面都感到不足,因此开始编写意大利面条式代码。 当我重新审视我的第一个功能时,我开始注意到我以前犯过的错误,并且我觉得自己可以做得更好。 供您参考,我的第一个功能称为“客户注册”,它允许新用户注册,而现有用户可以使用OTP功能登录。 这是该功能的技巧,但是随着我们深入研究,围绕它展开的逻辑很多。 对于这项功能,八月,我的上司创建了一个一次性密码库,我可以不时地对其进行修改,以适应该功能的需求。 代码气候测量 我们使用Code Climate来衡量我们的代码质量和可维护性。 在重构代码之前,我的PhoneNumberViewController和VerifyPhoneViewController的质量进行了如下测量: 继承方法 这里的计划是专门使用面向对象的编程继承,并且通过这种技术,我能够编写可伸缩且可测试的代码。 让我直观地向您介绍我们预期的代码结构。 为了让您更清楚地了解情况,我有两个父类,其子类数目灵活。 每个子类都将从父类继承,这样我就可以消除子类中的重复代码,并可以添加所需的任意多个子类。 让我以可视化的方式向您展示屏幕,然后给您一个场景。 作为新用户,我输入了我的电话号码,并被提示使用OTP代码进行注册。 然后,我通过短信收到我的OTP代码,并将其输入到我的验证屏幕上。 通过这种方法,我能够最大程度地减少代码中的冗余并拥有更简洁的代码结构。 但是,作为工程师,通过查看代码可以清楚得多。 我们将首先查看父类,在该类中,后端工程师创建了一个API,以检查电话号码以确定是否需要验证电话。 在满足不同条件的情况下,执行了不同的函数,但就我而言,我创建了几个空函数,这些空函数可以被子类覆盖。 比以前的分数高两个等级。 但是从可维护性来看,持续时间从24小时分别提高到25分钟和1小时有很大的提高。 我认为这是一个巨大的进步。 但是,我觉得我们仍然可以做得更好。 随之而来的是,所有子类创建的可维护性得分为A,0分钟。 快速而灵活地编写单元测试 我们将使用Quick&Nimble进行单元测试。 首先,我们将模拟自己的数据,而不依赖于API调用。 我们可以这样做,如下所示: 在这里,我们正在创建自己的模拟数据版本,以确定每个键的值,然后可以选择所需的返回值。 接下来,一旦有了模拟数据,就可以进行相应的测试。 首先,我们将测试电话是否被拿走,我们不允许用户注册。 我们可以通过选择checkNumberCase以返回我们需要的某些值来进行检查。 像往常一样,没有我的上校奥古斯特的帮助,我一个人不可能提出这种解决方案。 他在提出减少重复代码的解决方案方面做得非常出色,我得以在他的指导下实施该解决方案。 最后,我相信有很多不同的方法可以实现这一目标。 但是,我发现它可以以我的方式很好地工作,如果您以任何方式认为可以完成任何改进,请在下面随意评论。