Tag: 移动

如何在iOS应用中的框架之间建立桥梁

“我想导出应用程序的那部分,但它像面条一样与应用程序的其余部分绑定在一起!” 当我开始模块化我正在开发的应用程序的一部分时,我遇到了麻烦 。 我想将服务(实际上是跟踪服务) 导出到单独的 框架中 。 问题在于该服务很难与该应用程序绑定 。 它使用的是另一项服务,而该服务本身也使用了深入应用程序中的另一项。 为了导出跟踪服务,我将不得不在新框架中重构并重新制作整套服务! 但是事实是我没有时间这样做, 回归测试将是一场噩梦,并且由于任何其他公司可能会遇到的其他原因 (流程,预算,截止日期)。 因此,我不得不找出如何在 不重构所有内容的情况下 导出应用程序的这一部分。 让我们从一个具体的例子开始! 在这里, 学习和了解事物运作的最佳方式就是练习 ! (在这篇 文章的结尾,我将为这个例子提供 Github 仓库 ) 因此,让我设置上下文 ,我们有一个只有两个屏幕的小型应用程序: 主屏幕 付款屏幕 (我们希望将该屏幕导出到框架中 ) 付款页面包含一个用于输入卡号的TextField和一个Pay 按钮 。 当您按下按钮时,应启动付款。 但是! 挑战在于支付方式。 假设由于某些原因,我们无法 导出付款服务。

通用UserDefaults包装器

在上一篇文章中,我描述了如何为存储领域对象创建通用类。 但是,如果我们不想使用此类高级库并将数据保留在UserDefaults中,该怎么办。 我们也可以使用泛型类。 听起来很酷。 在开始时,像往常一样,我们必须创建我们的协议 并为我们的存储类实现它 就是这样。 现在,我们不仅可以读取或编写原始数据,而且可以读取任何符合存储协议的类。 您想要一些例子吗? 下面有更复杂的对象。 这里有完整的例子 感谢您的阅读! 如果您喜欢这篇文章,请鼓掌,以便其他人也可以阅读。 下一篇文章我也会有更多动力。🙂您还可以查看其他文章,也许您会找到适合您的东西。 如果您有任何问题或建议,请发表评论。

iOS 11上的拖放基础

iOS 11引入了通过拖放与应用程序中的数据进行交互的新方式。 拖放允许用户点击并按住UI元素,然后将其拖动到其他位置以执行操作,例如将与该UI元素关联的数据移动到新位置,创建其副本或将其删除。 在iPad上,可以在单独的应用程序之间执行此交互,从而为用户与多个应用程序进行交互提供了一种强大的新方式,并允许轻松,直观地复制数据。 拖放状态的人机交互准则用户希望该行为“在整个系统中普遍实现”。 如果是这样,通过使应用程序能够以以前无法实现的方式进行通信,可以完全改变使用多个应用程序进行多任务处理的动态。 在为Trade Me应用程序添加一些基本的拖放支持时,我对它的实现如此简单感到惊讶,并且我认为分享其工作原理的简单概述可能会很有用。 实施阻力 当用户长按想要移动或复制(或对其执行某些其他独特操作)的某些内容时,便开始拖动,该内容可能是UICollectionView , UITableView或我们应用程序中的其他内容。 在此示例中,假设我们的内容是一个集合视图,每个单元格代表一个相册中的一张照片,并且我们希望允许用户复制它。 为了告诉系统我们的集合视图内容是可拖动的,我们必须在集合视图上设置dragDelegate属性,并在UICollectionViewDragDelegate协议上实现collectionView(_:itemsForBeginning:at:)函数。 我们的collectionView(_:itemsForBeginning:at:)必须返回一个包含一个或多个UIDragItem实例的UIDragItem ,这些实例负责提供表示要拖动的项目的数据。 UIDragItem实例通过UIDragItem实例提供其数据,该实例用于通过NSItemProviderWriting和NSItemProviderReading协议在两个进程之间异步传送数据。 Apple提供的几种类型已经符合这些协议,因此,它们几乎可以在任何两个iOS应用之间传递,而在发送或接收应用中无需添加代码。 这些类型是NSString , NSAttributedString , NSURL , UIColor和UIImage 。 在我们的示例中,被拖动的内容是一张照片,因此我们可以使用UIImage来创建NSItemProvider的实例,该UIImage符合NSItemProviderWriting 。 这意味着我们无需编写任何代码即可将模型序列化为NSData表示形式,并且任何接受UIImage内容的应用程序都将允许用户将我们的内容放入其中。 值得注意的是,直到删除发生,系统才真正请求拖动的数据。 此时,系统会在源应用程序内的模型对象上调用loadData(withTypeIdentifier:forItemProviderCompletionHandler:) 。 实现下降 现在,我们已经完成了实现的拖动部分,让我们跳到接收应用程序,看看drop的实现是什么样子。 为了使我们的示例简单起见,假设用户将照片拖放到接收应用程序中的类似收藏夹视图中。 为了接收删除的内容,我们的集合视图必须设置其dropDelegate属性,并且必须实现UICollectionViewDropDelegate函数collectionView(_:performDropWith:) 。 此功能负责异步地从源应用程序中获取数据(如果拖动源自另一个应用程序,否则它可以同步发生),并将新内容设置为视图层次结构的动画。 我们的collectionView(_:performDropWith:)只需要迭代提供的UICollectionViewDropCoordinator的items ,并通过每个UIDragItem的项目提供程序上的loadData(withTypeIdentifier:forItemProviderCompletionHandler:)函数从源应用程序中获取相应的数据。 由于此操作是异步操作,因此在系统从原始应用程序请求数据并向用户提供反馈的同时,我们应适当地处理加载时间,这一点很重要。 我们可以在UICollectionViewDropCoordinator上使用drop(_:to:)函数为新内容创建一个占位符单元格。 加载完成后,我们只需要更新数据源并在新内容中设置动画即可。 我们可以使用创建占位符时返回的UICollectionViewDropPlaceholderContext上的commitInsertion(dataSourceUpdates:)函数来完成此操作。 我们的collectionView(_:performDropWith:)也应该能够处理源自同一应用程序的内容。 在这种情况下,我们可以简单地使用localObject属性将新内容插入到我们的数据源中。 有用的提示 我们要做的就是允许我们的两个应用程序之间进行基本的拖放交互,但是对于那些仍在阅读的人来说,这是我在探索这些API时发现的一些窍门。 NSURL是系统在本机支持下在应用程序之间传递数据的重要后备,并且可以通过通用链接链接到Web上或应用程序内的内容。 localObject属性仅在拖动项所源自的应用程序中可见,但对于轻松地将模型对象与拖动项一起传递到应用程序中很有用。 如果您要实现专门用于在iPhone上进行拖放操作,并且该交互仅限于一个应用程序,那么您可以只使用localObject而不必担心NSItemProviderWriting和NSItemProviderReading 。 实现collectionView(_:dropSessionDidUpdate:withDestinationIndexPath:)函数以返回UICollectionViewDropProposal ,该信号指示将内容放置在给定位置时将采取何种操作,以便系统可以向用户提供视觉反馈。 通过使用Apple提供的编码器和解码器(如JSONEncoder和JSONDecoder […]

您的代码签名文件可以吗?

在 Bitrise 上验证您的配置文件和代码签名身份, 并查看是否丢失或丢失了任何东西。 上周,我们在“代码签名”选项卡上进行了重大更改,并通过向其添加更多功能来使之更进一步。 打开应用程序的工作流程编辑器,然后单击“代码签名”选项卡。 您将在此处看到您的配置文件,或者现在可以添加一个。 您将在“显示匹配的证书,设备和功能”旁边看到文件的状态: 如果一切正常,您会看到一个绿点。 如果有需要修复的地方,您会看到一个橙色的点。 单击该按钮将弹出与上周介绍的相同的弹出窗口,但其他橙色圆圈将标记包含任何有问题的选项卡。 这些匹配的证书尚未上传: 注意:请同时在Code signing identities下的Code signing identities Code signing tab上检查配置文件的到期日期。 这些测试设备之一尚未在Bitrise上注册。 (加上从现在开始,您可以看到谁注册了该特定设备。) 我们希望此新功能可以使代码签名(以及您的生活)更加轻松。 🙂 让我们知道您的想法! 代码签名愉快! ✍ 最初发布在Bitrise博客上。

斯威夫特的BarChart

我想向您介绍我的解决方案,以创建自己的条形图而不使用任何第三方库。 图表库很多,但是我需要一些不同的东西。 我的主要目标是创建一个可重用的视图,该视图将显示带有X,Y轴和图例的图形。 在我的解决方案中,轴是从数据源自动缩放的。 例 资源 在这里您可以找到图表栏源代码,或者可以访问我的示例项目: sayler8182 /图表1 通过在GitHub上创建一个帐户来为sayler8182 / Chart1开发做出贡献。 github.com 感谢您的阅读! 如果您喜欢这篇文章,请鼓掌,以便其他人也可以阅读。 下一篇文章我也会有更多动力。🙂您还可以查看其他文章,也许您会找到适合您的东西。 如果您有任何问题或建议,请发表评论。

Swift并行编程:可能出什么问题?

在最后几篇文章中,我们研究了控制并发的不同方法。 操作系统提供了一些底层的基础知识。 例如,Apple提供了框架或其他想法(例如Promise),它们在JavaScript中得到了广泛使用。 即使前面已经提到了一些陷阱,但我意识到我没有给予他们足够的荣誉。 因此,为全面起见,本文进行了部分概述。 本文的目的是,如果您不了解并发性,可能会出错。 让我们潜入吧! 原子包含与数据库上下文中的事务具有相同的想法。 您希望一次将所有值写入一个操作。 当使用int64_t而不具有原子功能时,编译为32位的应用程序可能会出现奇怪的行为。 为什么? 让我们详细了解会发生什么: int64_t x = 0 线程1: x = 0xFFFF 线程2: x = 0xEEDD 进行非原子操作可能会导致第一个线程开始写入x。 但是,由于我们正在使用32位操作系统,因此必须将写入x的值分成两批0xFF。 当Thread2决定同​​时写入x时,可能会按照以下顺序安排操作: 线程1:part1 线程2:part1 线程2:part2 线程1:part2 最后,我们将获得: x == 0xEEFF 既不是0xFFFF也不是0xEEDD。 使用原子,我们创建一个单一的事务,这将导致以下行为: 线程1:part1 线程1:part2 线程2:part1 线程2:part2 结果,x包含Thread2设置的值。 Swift本身没有实现原子。 关于Swift进化,有一个建议添加它,但是目前,您必须自己实现它。 就在最近,我不得不修复一个崩溃,该崩溃是由于从两个不同的线程写入一个Array而导致的。 还记得Swift并发中的错误处理吗? 它包含一个错误,很容易忽略。 如果组中的两个操作可以并行运行并且同时失败,会发生什么情况? 他们将尝试同时写入错误数组,这将导致Swift.Array中的“分配容量”崩溃。 要修复它,该数组需要是线程安全的。 一种选择是:同步阵列。 但是通常,您将必须锁定每个写访问权限。 不要误会我的意思,阅读也可能会失败: 一个简单的例子是拥有一个银行帐户,需要执行交易。 此交易分为两个部分:第一笔提款和第二笔存款。 […]

如何使用UIImageView和UIScrollView滑动图像

这太容易了。 设置完项目后, 删除情节提要。 从现在开始,我将不会在演示图板上显示任何内容,也许以后我会谈论为什么,但请相信我,这是出于您自己的利益。 步骤2:将ViewController.swift设置为rootViewController 我们可以在AppDelegate.swift中轻松完成此操作。 如果单击Image Literal它将使您从放入文件夹的图像中进行选择。 因此,添加您想要的图像数量。 如果您不使用Xcode 8,或者想知道如何使用打字方式,则如下所示: 现在,我们已经在数组中包含了图像,我们可以创建一个循环遍历图像的函数,然后将其添加到scrollView中。 您不必像我一样将函数放在viewDidLoad之外,但我希望保持其干净。 这是我们的功能: 希望你不要对此感到困惑。 实际上,这很简单。 第一行说的是func setupImages(_ images: [UIImage]){ 这只是意味着我们有一个名为setUpImages的函数,它将使用UIImage数组。 现在我们有了for loop我们给循环赋予了变量i 。 i包含每个UIImage所以如果您有10张图像,它将循环10次。 很简单 我们还将imageView的图像设置为与images[i]相等。 它将遍历每个对象并设置图像。 然后,我们设置UIImageView的框架。 我们需要确保每个imageView不在同一页面上。 因此,我们将屏幕的宽度乘以i 。 这使我们的图像从不同的“页面”开始。 设置scrollView的contentView很重要,我们需要告诉我们的滚动视图需要多大。 然后,将其添加到scrollView的子视图中。 确保在viewDidLoad中添加scrollView并调用我们的函数: 就是这样,您应该可以运行它,然后在图像中滑动。 如果您有任何问题或建议,请在below以下评论。

Swift 4.0中的网络层

每当我开始一个新项目时,都会出现相同的问题。 如何实现网络层? 使用Moya,Alamofire等外部库或从头开始编写它。 我对这个问题的回答是–使用不带任何第三方库的纯Swift。 当然,实现面向协议的层非常简单,使用enum键入safe来配置端点并完全可测试。 在这几点中,您将学习如何编写可定制的面向协议的网络层。 在开始之前,了解URLSession及其组成类很重要。 通常, URLSession负责发送和接收HTTPRequests 。 对于基本请求,您可以使用没有配置对象的shared会话。 它不像您自己创建的会话那样可定制,但是如果您有非常有限的要求,它可以作为一个很好的起点。 对于其他类型的会话,您URLSession使用以下三种配置之一实例化URLSession : .default –会话表现为共享会话,但允许进行更多配置并使用委托增量获取数据。 .ephemeral –会话也类似于共享会话,但是不要将缓存,cookie或凭据写入磁盘。 .background –会话使您可以在应用程序未运行时在后台执行内容的上载和下载。 URLSession以两种方式返回数据: 完成处理程序 在委托上调用方法 在会话中,您可以创建URLSessionTask以从服务器检索数据,上传照片或下载文件。 此外,您还可以继续,暂停和取消任务。 URLSessionTask提供了暂停运行任务的机会,例如,当用户离开应用程序时暂停任务,并在返回时恢复任务。 URLSession提供三种类型的任务: data –使用Data对象发送和接收数据。 数据任务旨在向服务器发出简短的,经常是交互式的请求。 upload –与数据任务相似,但通常用于在应用程序不运行时上传文件并支持后台上传。 download –以文件形式检索数据,并在应用程序未运行时支持后台下载和上传。 在本教程中,您将仅使用第一种URLSessionTask来发送请求并处理服务器的响应。 简要回顾一下URLSession可以做什么URLSession ,现在让我们进行一些练习。 首先,您必须将网络层划分为小型服务。 将所有请求都保存在一个类/枚举中是很难维护的,并且可能会变成一个庞然大物。 ServiceProtocol将帮助创建URLRequest 。 ServiceProtocol包含构成组件,例如baseURL,路径,方法,标头,任务和parametersEncoding。 继续创建您的第一个简单网络层文件。 HTTPMethod是一个枚举,负责设置请求的HTTP方法。 URLRequest具有.httpMethod属性以设置方法的字符串类型。 Task是一个枚举,负责为特定服务配置参数。 您可以添加适用于您的网络层要求的情况。 例如upload(Data) , download(parameters: Parameters)等。该示例只有两种情况可以发送普通请求或带有参数。 ParametersEncoding是负责设置编码类型的枚举。 在此示例中,您必须使用最流行的:URL和JSON。 瞧! 创建网络层的第一部分已经完成。 […]

编码-序列化变得容易

随着Swift 4和iOS 11的到来,以及XCode 9 GM准备将应用程序发送到AppStore,我们必须为可用的最新技术做好准备,以为用户带来最佳体验。 我们实现这一目标的方法之一是使产品更易于编码,阅读和维护。 这也可能导致更快的创建过程和对社区的更快反应。 今天,我想写一件事,您可以做一些接近最终效率的事情-可编码协议。 我非常相信,如果您在这里,您可能对序列化和JSON 有所了解。 尽管人们可以花大量时间来解释什么是Codable以及它如何工作,但我将专注于一件可能不那么容易处理的事情-具有相关价值的枚举。 假设我们要给非iPhone-X用户一个发送动画表情符号的机会。 我们需要处理枚举“ Animojis”,其中要考虑到iPhone X发送的真实动画和普通表情符号,用户希望我们将它们与我们的高端技术动画化,其唯一目的是模拟卡通图标的运动。 很基本吧? 编写自定义解析器应该是一件容易的事,但是……嘿! 使用Swift 4和iOS 11,我们不想这样做! 让我们先关注编码。 为此,我们必须提供一个Encodable结构,该结构将保留枚举实例的关联值。 让我们从非iPhone-X手机壳开始。 现在我们可以实现Encodable协议并使用可用的编码功能,因为该结构的所有属性都是开箱即用的Codable协议支持的类型。 现在,您可以使用Apple的JSONEncoder创建漂亮的 JSON! 让我们尝试一下。 如果我们打印json变量,我们可以看到: 没有明确指示这实际上是什么情况,因此我们必须花很多精力来解码JSON,尤其是对于更多的中间场景。 必须应用一些修复程序。 让我们来看看json变量下的内容。 这样更好 构造我们想要的数据非常容易,并且不需要涉及任何键或解析。 但是解码呢? JSON已准备好共享,因此我们也应包括解码。 为此,我们必须使Animoji枚举符合Decodable协议,并且由于它已经符合Encodable,因此我们可以简单地用Codable替换它,并从Decodable协议中添加缺少的init并修改结构。 这是更改的结果。 现在,让我们尝试对通过编码创建的数据变量进行解码。 在XCode Playgrounds中,我们可以看到在result变量下有我们心爱的:poop:emoji表情。 成功! 我希望本快速阅读为如何处理Codable协议提供一些启示。 还有其他一些方法可以解决此问题,例如实现CodingKeys或手动从解码器容器中提取值,但引起我注意的是本文中介绍的处理这种情况的方式。 如果您根本不熟悉Codable协议,建议您遵循此综合指南。 我希望您发现它有些用处/有趣,不要犹豫分享它或在下面的评论中留下反馈/问题。

迦太基的第三方依赖管理

依赖关系-它们是什么?如何使用它们? 软件开发的核心是软件重用,或者利用现有代码进一步开发新的和将来的代码。 正是基于这种心态,团队能够专注于眼前的问题,而不会浪费时间来重新发明轮子。 重用的代码可以是基础构建块,也可以只是方便使用的通用组件库,无论哪种方式,都不直接针对当前的问题。 这些组件称为依赖项。 用软件项目管理这些组件的集成称为依赖管理。 该过程具有与之相关的相关开销,这是不可避免的,但却是必需的。 在移动软件开发方面,以下是依赖性管理的几个选项,并在Compass上提供了有关如何管理依赖性的深入指南。 Git子模块 Git子模块是git存储库的原始依赖项管理器。 它们提供了一种定义应用程序使用但由项目存储库外部存储和管理的其他存储库的方法。 子模块是将依赖项添加到项目中的一种非常手动的方法。 它将从存储库中签出该代码,就是这样。 移动应用程序缺少此工作流,因为通过原始源代码使用已编译的库或框架要容易得多。 椰子足 Cocoapods是iOS和Cocoa应用程序的依赖项管理器,它抽象了依赖项管理的详细信息。 它下载依赖项并将其集成到Xcode工作区中。 让我们通过Xcode的工作区为您完成集成 Cocoapods最大的特点是,依赖项的自动化可能是其最大的缺陷。 在Compass,我们相信您永远都不应束手无策,而会厌倦神奇的解决方案。 依赖关系集成不是一件容易的事,最好不要假设它可以以一种适合所有命令的方式实现,请参见图A。 迦太基 迦太基是“可可的一个简单,分散的依赖性管理器” 迦太基不仅简化了子模块的工作,而且不仅通过检查依赖关系存储库,而且还将代码构建为易于集成的框架,使其可用于移动应用程序。 这就使框架集成工作留给了开发人员,消除了流程中的歧义和不必要的自动化。 在Compass,我们非常喜欢迦太基而不是Cocoapods。 迅捷软件包管理器 最后,我们有了相对较新的Swift Package Manager。 Swift Package Manager是用于管理Swift代码分发的工具。 它与Swift构建系统集成在一起,以自动化下载,编译和链接依赖项的过程。 Swift Package Manager正在发展声望,成为iOS依赖管理中的下一件大事。 不幸的是,由于严格限制仅使用Swift和其选择加入的性质,它尚未实现其成为主流的目标。 如果并且直到那一天到来,我们的团队将使用Carthage进行我们的所有iOS依赖关系管理,并强烈建议您这样做。