Tag: 泛型

泛型

迅捷泛型 许多人可以理解泛型,阅读泛型代码并遵循代码,但发现使用泛型编写代码或避免使用泛型是很困难的。 让我们可以轻松地考虑适当地使用泛型。 Swift是强类型语言,也是静态类型语言。 当我的意思是强类型时,每个函数参数或返回类型都需要一个类型,并迅速检查传递/返回的值是否属于该类型,否则会发生编译/运行时错误。 当我说静态类型时,我的意思是swift仅检查所有这些编译时间,否则抛出错误。 好吧,如果您想告诉编译器我不确定我将处理的“类型”是什么,并且它可以是动态的? 多数民众赞成在我们排序到动态打字。 但是,使用像Swift这样的强静态类型语言,我们如何实现呢? 那就是泛型出现的地方。 假设您实现了可快速处理“字符串”的STACK,它将类似于以下内容: 现在,说我希望能够实现一个存储整数的堆栈。 最后,我将写另一个与上述完全相同的Stack数据结构,其中函数和返回类型的参数为“ Int”而不是String。 可以这样说,我可以根据需要的数据类型创建动态dataType结构实例。 当然,在实例化时,您必须指定要查找要存储的堆栈的数据类型。 在下面的代码中,其表示为。 注意:T可以是任何东西。 U也可以说G或A或ZZ或GENERIC。 注意:编写任何通用代码的最佳方法是,在我的案例String中编写代码以采用特定的数据类型,然后将其替换为T。在我们的示例中,定义Struct的定义方式为Struct GenericStruct 。 实例化时,请查看其用法。 GenericStruct ()。 任何与泛型 您总是可以说,好吧,我将通过使用下面的Any来解决此特定问题-> 那为什么要泛型呢? 好吧,它解决了特定类型的问题。 参见下文。 泛型基本上告诉编译器:“稍后我将为您提供一个类型,我希望您 在指定的任何地方 强制执行该类型 。” AnyObject基本上告诉编译器:“不用担心这个变量, 无需强制执行任何类型,在这里 我可以做任何想做的事情。” 如果要使用协议,泛型将如何适合那里? 这可能真的很有用。 这是associatedTypes和typealias出现的地方。 请查看以下内容,如何通过类型别名将协议中的项目与动态类型T相关联:

通用表视图控制器

嘿伙计! 今天我们将讨论通用的东西,看看上面的图片。 你看到了什么? 提供一些屏幕的简单iOS应用程序导航流程。 他们有什么共同点? 乍一看,我们可以观察到基于TableViewController构建的四个屏幕,对吗? 你同意吗? 可能最直观的方法是构建五个视图控制器来完成此应用程序,但我想分享一种方法,我们将仅使用两个方法。 一个用于所有列表屏幕中使用的通用表视图控制器,另一个用于显示未找到的屏幕,第二个视图控制器的构建只是为了证明您可以将另一种视图控制器与我们将要展示的概念集成在一起的概念。这里。 在本文的最后获得GitHub上的完整代码。 有什么变化? 如果您看一看,确实会注意到这些表格视图屏幕中的单元格正在发生变化。 因此,我们可以将表视图作为通用组件重用,并自定义所需的任何单元格。 为了使用故事板实现此目标,我认为这很困难,我不会说不可能,但是我花了很多时间,而且我也找不到一个优雅的解决方案,这主要是因为我们必须告知通用类型,并告知通用视图控制器和方法情节提要实例化不利于此。 因此这是一个复杂的主题,当然也有优点和缺点,如果您想了解更多信息,我在下面的链接中写了一篇关于该主题的文章: 什么? 以编程方式进行布局? 你疯了吗? 我为什么要这样做? 当我第一次听它时,我承认这听起来很奇怪。 一个聪明的同事向我和我建议了… medium.com 因此,为了实现此目标,我使用了程序化的视图控制器,请看以下内容: 上面的代码具有执行表视图控制器表示所需的全部内容,并且具有(cellForAt)方法,numberOfRowsInSection和didSelectRowAt方法已实现。 注意构造函数推断出的通用类型,该通用类型有一个约束,并且它必须符合协议DescriptiveProtocol才能为(cellForAt)方法中的每个项目提供绑定UITableViewCell的方法。 因此,以这种方式,数据源中的每个元素都必须告知必须通过表视图中的可重用出队方法返回哪种单元格类型。 这是窍门,通用表视图对单元格一无所知,因此可以将其用于所有单元格。 描述符对象负责保存单元格类型,重用标识符和配置单元格必须调用的闭包。 如您所见,此结构符合DescriptiveProtocol,并且具有称为描述符的属性,如上所述,它有责任将其绑定到UIViewTableCell专业化,这时将在调用表视图cellForAt方法时通知单元格类型。 其余代码是不言自明的,我认为这不是灵丹妙药,但是可以在某些特定情况下帮助某人,如果您有话要说,请随时发表评论。 再见,下次见。 heuristisk / hkImperatorMensa hkImperatorMensa –通用表视图控制器 github.com

使用Swift泛型处理单元动作

给iOS开发人员一个 表格视图 ,他将编写10多个有关如何处理单元格操作的实现。 由于我们在Chili Labs中经常处理表格和集合,因此我想提出一个通用的解决方案,以解决项目中的单元动作。 我之前的文章中介绍的使用单元配置器的解决方案效果很好。 因此,将其作为基本模式可能是一个好主意。 首先,让我们添加TableDirector类,该类将存储单元配置器,并将成为UITableView的委托和数据源。 首先,我们需要向CellAction枚举中再添加一种情况,并返回其hashValue。 这里最具挑战性的事情是如何将自定义操作传递给CellActionProxy对象。 可以通过NotificationCenter发送通知来完成。 我们可以为CellAction枚举添加扩展,以方便地发送通知。 动作数据将存储在结构中,并通过userInfo参数发送。 最后,我们需要在TableDirector类中订阅并处理通知。 现在我们可以调用“跟随”动作并进行处理。 而已! 现在,我们有了一种机制,可以通用地处理任何单元操作。 进行少量修改,即可用于处理UICollectionViewCell操作。

Swift中的通用可选处理

有时,您希望编写一种适用于任何Optional类型的通用算法,无论包装在里面的是哪种实际类型。 好的,这可以使用免费的泛型函数轻松完成,但是例如,如果要编写Sequence扩展以删除所有nil值怎么办? 由于Optional不是协议而是具体类型,因此事情变得有点复杂,因此不能将其用作通用类型约束。 Swift中的通用协议和具体类型具有不同的用途:我们创建实例并声明具体类型的变量,而协议则可以用作通用类型约束。 类型擦除是一种在我们要声明一个能够容纳符合特定协议的任何具体类型的变量时使用的技术。 相反,我们想要的是同一难题的另一部分,我们需要一个协议,允许我们将具体的泛型用作约束。 用英语听起来这听起来很复杂,但通常情况下,用普通的Swift编写起来看起来要简单得多。 因此,这里我们只定义一个OptionalType协议,声明WrappedType关联的类型,并使Optional枚举符合该类型。 请注意,泛型类型参数不会自动满足协议要求,但是这里我们有类型推断。 为了使该协议有用,我们公开了一些基本的Optional功能: asOptional属性使我们可以访问可选的绑定语法。 ExpressibleByNilLiteral一致性允许我们使用nil进行初始化。 完成之后,我们现在可以将OptionalType用作一般约束: 如果您正在寻找可以使用Optional枚举完成的更多技巧,则应查看Russ Bishop撰写的精彩文章。

迅捷泛型

Hola技术人员,直到现在我们所有人都已经阅读了许多有关最酷的主题泛型的博客和文章,但仍然有模糊的想法吗? 让我们尝试再次擦拭灰尘。 通用功能使程序更灵活,可重用和可伸缩,可以与任何类型的数据类型一起使用。 泛型是Swift非常强大的功能。 大多数基于泛型的库和框架。 甚至我们在日常编码生活中都使用了泛型而不了解它。 示例:数组和字典都是swift的通用集合类型,它们可以容纳任何类型的数据类型,例如Int,String,CGPoint等。让我们不必过多谈直接进入一些实际的东西。 让我们编码… 假设我们有一个电子商务应用程序,并且必须在该应用程序上的大部分位置显示金额标签,并且金额也来自服务器,而该服务器也不是特定的数据类型,有时是Int,Float,Double并可能是String本身。 因此,我们通常要做的是。 每次都厌倦了类型转换,如果我们得到一个函数,可以传递任何类型的数据类型,该函数会将其转换为带有$($)的字符串,以便将其直接传递给我们的UILabels或UIButtons。 是不是很酷。 在上面的扩展中,我们符合我们的协议,在该协议中,我们还将返回Double和String的转换,并附加了美元货币。 我们必须对所有数据类型实施相同的操作。 现在将在我们的Utilities类或Global类中编写一个全局函数amountText ,可以在整个项目中访问它而无需创建任何实例。 将使此函数公开,以便它也可以在模块外部使用,默认情况下,它将在内部使用,因此不能在定义模块之外使用。 此函数将采用通用数据类型,该数据类型均符合我们的协议AmountConversion 。 现在,使用我们的标签和按钮检查它是否可以接受。 来吧,我们来创建一个UILabel和一些带有若干数据类型的实例。 这是可以预期的数量。 并尝试直接将其与标签文本一起传递。 在这里,我们在协议中创建了一个初始化程序,这将有助于我们在通用方法中返回默认值,将在下一节中讨论它。 再次来到您的Utility或Global类,并编写一个通用方法。 它将接受所有符合我们的协议UnwrapOptional的任何类型的参数。 现在让我们创建一些可选的变量,并检查我们的函数是否给出了预期的结果。 下面一些变量具有值,而另一些则为零,让我们看看函数返回给我们什么值。 哇哈哈! 我们得到了期望的输出。 现在将进一步扩展此功能。 如果我们有任何自定义类或自定义类,在其中也有可选的var可以使用,那么它也可以是可选的链接。 能行吗 我们来看看 我有电影类,现在有一些可选变量尝试用电影类型的实例解开可选对象。 YOOO,之所以起作用,是因为最终我们试图解包已经符合我们的UnwrapOptional协议的字符串或指定的数据类型。 现在查看是否尝试解开Movie类的实例。 没运气! 它将出现错误“在参数类型’电影?’中,’电影’与预期的类型’UnwrapOptional’不符” 因此,在这里我们必须使我们的类符合协议。 并且它将为类添加必需的init,因为我们的UnwrapOptional协议具有自己的构造函数,可返回自定义类的默认值。 是的,任务完成了。 现在,我们可以尝试使用可选链接获取值。 抢啤酒! 干杯! 它的工作原理,足以满足一天的学习需求。 好了,我们了解了泛型如何与协议握手,并解决了许多问题。 泛型有很多附带功能。 欢迎反馈。

Swift中带Codable的不确定类型

可在此处找到该帖子的配套游乐场。 时光飞逝。 Swift 4.0于2017年9月发布,并且一段时间以来我们一直在享受Codable协议。 但是,我们仍有一些基础。 回想一下, Codable协议使对符合该协议的值进行编码和解码变得非常容易。 哦,它带有属性列表和JSON支持。 还记得Swift 4之前无数的JSON解码库吗? 在大多数情况下,当您声明采用Codable的类型时,编译器将完成大部分工作并合成一致性 。 如果JSON键与属性名称不匹配,则可能还需要指定CodingKeys枚举。 但是,在某些情况下有必要手动实现Codable 。 其中的一种就是使用JSON包含对象,这些对象的类型由”type”键的值确定。 考虑一个假设的Messaging API ,它支持各种附件:图像,音频等。 { “ from”:“ Guille”, “ text”:“看看我刚刚发现的东西!”, “附件”:[ { “ type”:“ image” , “有效载荷”:{ “ url”:“ http://via.placeholder.com/640×480”, “宽度”:640, “身高”:480 } }, { “ type”:“ audio” , “有效载荷”:{ “ title”:“永不放弃你”, “ url”:“ https://audio.com/NeverGonnaGiveYouUp.mp3”, “ shouldAutoplay”:是的, } } ] […]

Swift中的Type Erasure

在上一篇文章中,我写了关于将代码拆分为较小框架的文章。 但是有时候这说起来容易做起来难。 我当前的挑战是调制可重用的UI处理。 这就是为什么我创建FancyUI。 除了某些配置扩展之外,我还为主题支持实现了组件管理器。 FancyUI中的样式表和组件管理器 可样式设置是继承可样式设置协议的视图。 它们强制您实施style(colorScheme:)方法,以便您可以配置视图的颜色。 您可以在组件管理器中注册它们。 组件管理器充当观察者,而可样式元素本身就是主题更改的侦听器。 您可以通过组件管理器轻松传递新的颜色方案,以轻松管理应用程序中的主题支持。 问题 FancyUI的实现应该能够创建自定义ColorScheme类型。 因此,Styleable必须对ColorScheme使用通用类型。 可样式化是一种协议,因此ColorScheme必须是关联的类型。 组件管理器(它是一个结构)保存ColorScheme并将其传递给已注册的styleables。 这就是问题所在:因为组件管理器是struct,所以它具有通用类型GenericSchemeType而Styleable具有关联的类型SchemeType 。 我必须将通用SchemeType转换为关联类型SchemeType ,这是不可能迅速实现的。 解决方案:类型擦除 问题是在编译时无法推断类型。 这就是为什么我试图创建一个结构AnyStyleable。 此类型将样式函数存储为闭包,并在调用style()函数时执行它。 组件管理器现在注册AnyStyleable而不是Styleable。 注意:类型信息并没有真正删除。 它已经搬迁了。 闭包在运行时推断其类型,因此我们在这里没有问题。 该问题已解决。 但是我对解决方案有一个体系结构上的问题:样式类型必须另存为闭包,而视图本身不是Styleable。 正如我已经提到的,我喜欢提取东西。 我想象在一个大型的成长型企业应用程序中使用样式方法。 在viewDidLoad或init中设置AnyStyleable会使事情变得blo肿,因此我对Styleable协议的初衷是在单独的扩展中实现它(并让视图控制器本身作为Styleable本身)。 因为样式位于另一种类型,所以这不可能了。 但是我也有解决这个问题的方法。 替代方法:实型擦除 在我目前的方法中,原始的Styleable协议没有太大变化。 几乎是一样的,除了协议是由另一个协议继承的:AnyStyleable.AnyStyleable是一个将样式函数作为闭包的结构,现在它是一个将style(scheme:)方法定义为Any类型的协议。 这意味着:AnyStyleable是具有具体类型的协议(即使它是Any)。 这使我们可以将AnyStyleables注册到组件管理器。 魔术来了:正如我提到的,Styleable协议继承了AnyStyleable协议。 因此,我可以将Styleables注册到组件管理器,因为它正在等待AnyStyleable的类型。 您现在可能会问自己:可样式设置具有 style(colorScheme:) 方法。 当它们实际注册为AnyStyleable时如何调用? AnyStyleable协议定义_style(colorScheme:)方法,该方法作为默认实现实现。 _style(colorScheme:)实现在运行时检查传递的类型是否与关联的类型匹配,如果成功,则调用style(colorScheme)函数。 因此,实际上,组件管理器调用_style(colorScheme:)方法,该方法在运行时委托给style(colorScheme:)方法。 这种方法的好处是实现完全不必处理擦除。 它可以只调用所使用的register(self) ,并且可以将实现的样式函数提取为扩展。 结论 我通常会尝试避免类型检查和类型转换。 但是这种方法对我来说似乎是合法的(也是因为它已用于标准库中的某些类型)。 […]

只是我的类型! — Swift中的自定义类型和错误处理

在坐下来编写代码之前,重要的是解决您需要处理的第一个错误,而不是try -ing。 阅读文档或花时间学习错误处理并不是大多数人都觉得有趣的时光。 起初绝对不是我的。 但是,在探索了有关该主题的一些教程和当代文献之后,我发现在构造自定义类型以处理错误方面有一定的赞赏。 无论您是终身使用的Swift开发人员,还是刚入门的人,都有可能听说过Functional Programming 。 函数式Swift是一个很棒的资源,它是Swift中函数式编程的简介。 尽管此资源着重介绍了许多很棒的主题,但我发现有关枚举和Swift错误的部分在我的项目中特别有用。 这篇文章将带您浏览一些受这些部分启发的示例。 以下示例可在我的演示存储库中的操场上找到。 随意克隆或下载仓库,然后继续! 我确定我们已经编写了所有方法来检查数组或字典中的某些值。 这些容器类型是Swift标准库的一部分,是iOS开发不可或缺的一部分。 在下面的示例中,我们将优化一种方法,该方法仅使用个人的memberName来检索团队成员的数量。 但是,要获取团队成员的数量,需要先查找团队。 构建此方法的合理方法可能如下所示: 使用可选的返回类型 func numberOfTeamMembers(memberName:String)->整数? {卫队让team = teamNames [memberName]否则{return nil} 后卫让号= teamMembers [team] else {return nil} 返回号码 } 然后,我们可以像下面这样在我们的代码中调用此方法: let someLookup = numberOfTeamMembers(memberName: “Tommy”) 还不错吧? 我们的numberOfTeamMembers(memberName:)方法将返回可选的Int? 如果查找成功。 否则,如果其中一项检查失败, someLookup将包含nil 。 尽管这似乎是解决问题的一种合理方法,但我们对查找失败的原因一无所知。 换句话说,如果上述方法返回nil ,那么我们将不知道哪些检查没有通过。 对于更复杂的方法,在跟踪查找错误的来源时可能会出现问题。 numberOfTeamMembers(memberName:)方法的缺点之一在于其返回类型Int? 。 如果我们可以创建自己的返回类型怎么办? 具体来说,如果查找成功,则可以返回Int的类型,如果查找失败,则可以返回详细的错误。 为此,我们可以尝试如下操作: […]

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,以后将是快速错误类型。 结果类型 […]

类型安全的用户默认值

以前,我们只是通过使用字符串键将数据存储在UserDefaults中。 每当我们需要照顾数据类型时 。 setBool(_:forKey:_)和co是解决方案。 可是等等?! 如果您需要获取给定密钥的值怎么办? 您需要遍历代码库并检查在那里存储了什么类型:它是Int吗? 或数组。 这是浪费时间,甚至如此危险:您可以在此处存储Bool,其他人可以存储任何其他类型。 但是您可以确定这是一个布尔型,并且解开nil可选项可能会导致崩溃。 我为什么过去说话? 因为自Swift 3推出以来,一个不错的解决方案就可以实现。 setValue(_:for key:_)方法现在接受Any值,不再接受AnyObject :这使事情变得更加容易。 让我们看看如何: 使用泛型,我们可以定义一个简单的DefaultKey结构,该结构包含要存储的类型和键名信息。 这样,您可以轻松地在常量文件中定义DefaultKey集 完成此操作后,您可以轻松地为UserDefaults构建通用扩展,如下所示 这个小界面可让您获取或设置存储的值,而无需关心值的类型 如果您尝试为LaunchesKey存储字符串会怎样? 实际上,此界面会自动提醒您应为定义的键存储什么类型。 检查我的Github存储库上的完整代码:https://github.com/dalu93/Defaults 更新:使用Swift 4现在可以实现通用下标。 有关更多信息,请查看GitHub上的develop分支。