Tag: swift

读者进行环境注入

好吧,想象一下那些为孩子们准备的贴纸书 ,其中有一些孩子可以放在不同背景下的贴纸。 例如,他可以拿牛贴纸,并贴在田野中,山峦和河流在流淌。 或者,他可以将牛放在实验实验室,空间或马戏团中……这本书提供了许多不同的景观供您选择。 结果是一个场景,其中母牛在田野,马戏团或太空中嚼嚼嚼的东西,尽管那里可能没有很多草可以咀嚼…… 孩子首先从书中的贴纸页面上拿走贴纸,然后决定将其放置在哪里(大多数情况下遵循完全随机的逻辑),最后将其放置在特定的环境中 。 然后他可以再贴上一张贴纸,一头母牛在做别的事情(跳跃,睡觉等等),或者另一头人物在做什么。 你明白了。 注入上下文 好吧,回到成年人的世界,那里不再有贴纸玩(除非有孩子)。 假设您正在构建一个应用程序,并且在某个时候您从存储库中获取了一些数据。 它可以来自任何来源,网络或本地,都没有关系。 假设您正在构建社交应用程序,并且需要为特定的电子邮件吸引用户。 您将拥有一个带有以下签名的方法: func getUser(email:String)->用户 在此示例中,按照我们的不干胶标签书类似, 不干胶标签是电子邮件, 结果是User对象。 但是实际情况在哪里? 景观是发生所有这些事情的背景,在贴纸书中是马戏团或田野。 在我们的小示例中,它可能是我们正在访问的特定存储库以获取数据: Web服务 ,成熟的持久层或测试模拟(其中可能没有任何东西可嚼)。 对于我们的应用程序,我们称其为服务 。 那么,我们如何让上一个函数知道要使用哪个服务,即应该从哪里获取数据呢? 换句话说,我们如何注入服务? 直接的解决方案可能只是将另一个参数传递给函数。 func getUser(email:String,service:Service)->用户{ 返回service.findUser(withEmail:email) } 现在,该服务访问存储库,以返回用户以传递我们传递的电子邮件。 目前,我们正在忽略各种错误。 这非常好,因为现在出于测试目的,我们可以用其他符合相同协议的东西来代替服务。 尽管这种方法没有错,但是这意味着现在这种类型的每个函数都必须包含服务参数。 向服务参数添加默认值可能看起来更简单,您可以再次使用以前的函数签名,该服务将成为默认服务。 但是,随后您使对服务的依赖关系变得隐含了 ,API用户很难看到它。 还有另一个问题,可能很难看到。 使用这种语法,函数的调用者将必须传递userId和服务,换句话说,在进行调用时必须知道该信息。 乍看之下,两条信息是完全不相关的:用户的ID和获取该用户的服务。 对于此函数的调用者,我们正在混合两种完全不同的职责 :业务逻辑和持久性或网络代码。 替代。 读者 您是一名优秀的程序员,因此您希望将职责分开。 您相信SOLID中的“ S”,因此一类必须只有一个改变的理由 。 我们需要改进该代码。 如果还有另一种方式怎么办? 如果我们可以从函数中删除service参数,并获得允许部分应用的结果值,该怎么办? […]

2016年のマイ人気记事ランキング👀

2016年もたくさん记事书きました。2015年にQiitaに色々记事书き始めて,そこから记事を书く习惯が続いていて良い感じです。 中— mono0926 iPhone 7 Plusを,シャワー中に使ったり水ですすいだりしてたら,水没判定で有偿交换となってしまった话 苹果手表Nike +を使った感想 夫妇で使う 雨燕メルマガを始めました macOS SierraでWindowsキーBOードがようやく问题无く使えるようになりました🎉 家庭で手軽にできる,家电の自动化・リモート操作事例集🤖 UIColorの定义はすべて#colorLiteral使ってみることにしてみた 情报收集のための11の质问に答えてみる Swiftポエム— null安全编 アウトプットする场は适当に分散しちゃっても良いかなという话 iPhone 7 Plusを,シャワー中に使ったり水ですすいだりしてたら,水没判定で有偿交换となってしまった话 10万PV以上行きました(´・‿・`) 雨燕メルマガを始めました 今年始めた活动としては,こちらが大きいです(・‿・`) Swift ・ iOSメルマガ(Swiftレター)を毎周配信して3ヶ月経った所感🎅 iOS App Calendar 2016の25日目の记事です(・‿・`) ※本记事は纯粋な技术情报少なめです,すみません 🙇medium.com アウトプットする场は适当に分散しちゃっても良いかなという话 去年は,技术系记事もQiitaではなくMediumで书いてたりもしましたが,そのあたりの思いはこちらに书いてあります。 Poと,AirPodsの记事も书きたいと思いつつ手つかずです…。AirPods最高です(・‿・`) 出版物も随时作っています 运用ンジニアの家庭运用提示 斯威夫特·iOSコラム ガジェットポエム あと,こっそり技术书ノートも作っていますが,技术书全然読めてないのでダメです(´・(・`)今年はがんばりたいです。 Qiita — mono0926 Meidumは,Google Analytics(分析)は独自ドメインでしか使えないので,上のMedium Notebookランキングは手动グは(・‿・`) iOSのPUSH通知(APNS)の特徴・ノウハウまとめ(iOS 9まで対応)— Qiita Sublime TextからVisual Studio代码に乘り换えた话— Qiita URLスキーム・独自ディープリンク実装に代わる,Universal […]

单元测试和测试驱动开发(Xcode 8和Swift 3)

使用单元测试时,您将使用代码来测试项目,而不是运行模拟器并浏览应用程序。 在开发时,测试不是必要的做法-但是,如果您设置了良好的测试,它会使构建和重构代码更加安全。 我们可以使用代码测试代码的方法是将函数结果与预期结果进行比较。 因此,如果我们有一个函数返回两个整数的和,则可以给它提供具有预期结果的参数。 因为我们知道2 + 3 = 5…如果函数返回5,则测试将通过,否则测试将失败,并且我们知道需要修复函数。 许多开发人员练习测试驱动开发(TDD)。 TDD涉及在编写与该测试关联的生产代码之前编写测试代码。 在本文中,我将构建一个使用单元测试和TDD的简单项目。 设置项目 要在项目中使用单元测试,需要与主项目建立一个单独的目标。 您可以通过在创建新项目时取消选中“使用单元测试”框来实现。 如果您已经创建了项目,则可以通过在Project Navigator中选择项目 ,选择“ Targets”下的“ +”按钮,然后选择“ iOS Unit Testing Bundle”来创建新目标。 在这两种情况下,Xcode都会创建一个新目录,默认Info.plist和.swift文件。 .swift文件包含一些可以在XCTest框架中使用的函数示例,但是我们将从头开始创建自己的文件。 设置测试.swift文件 为了使事情井井有条,我将为项目中的每个.swift文件创建一个tests.swift文件。 为了说明这一点,我将在项目中创建两个新的.swift文件,然后再创建相应的tests.swift文件。 由于我们在这里进行TDD练习,因此让我们从为Math.swift文件中的代码创建一些测试开始。 我将跳至我的MathTests.swift文件并设置该文件进行测试。 设置tests.swift文件时,您将要导入XCTest框架和包含@testable的项目。 这允许单元测试在您的项目中查找测试中定义的任何类。 接下来,我们将该类定义为XCTestCase的子级。 我还包括一个初始变量和两个函数。 “ setUp”函数在类中的每个测试方法之前被调用,而“ tearDown”在每个测试方法的末尾被调用。 如果需要,您可以进行一些自定义-但在我们的示例中我们将不需要它们。 现在,在编写生产代码之前,我已经以真正的TDD方式编写了测试实现的一部分。 由于我的Math.swift文件没有任何代码,因此测试无法找到它。 因此,让我们转到Math.swift文件并声明该类以解决此问题。 快速构建后,错误已修复! 请记住,由于我们导入了项目,因此可以在项目中使用类声明变量。 编写数学测验 我们想要一个包含3个整数的函数,该函数获取前两个整数的和并将其乘以第三个整数。 由于我们正在练习TDD,因此让我们先编写测试。 这是测试功能的基本结构: 为了在运行测试时调用该函数,名称必须始终以“ test”开头。 这里的函数名为“ testAddAndMultiply”,因为我打算在我的数学类中创建一个名为“ addAndMultiply”的函数。 接下来,我们看到“ XCTAssert”,它实际上是一个函数。 […]

Swift通过Zip,Map和Reduce进行有用的操作

今天的文章是Swift中的zip,map和reduce函数。 让我们介绍一下您在编码工作中可能遇到的一个典型问题。 问题陈述 您正在使用学校评分应用程序,该应用程序允许教师监视学生的进度。 您可以获得有关班级中每个学生的信息以及他们的作业和测验成绩。 所有这些信息都可以存储并可以用JSON检索,这意味着您最终可以拥有结构化的数组和数据字典。 到目前为止,一切都很好。 但是,你的老板想要改变。 她已要求您给老师更多的方法来分析学生的表现。 尽管可以在服务器上完成此工作,但她希望看到客户端应用程序中已完成的功能以最大程度地减少网络流量以及其他一些她没有详细说明的原因。 免责声明-这是一个人为的示例,我们将简化一些假设,以使问题与zip,map和reduce上的课程一起解决。 让我们看一下如何开始使用zip,map和reduce函数来解决其中的一些挑战。 压缩 zip方法允许您使用数组,集合,字典(或符合SequenceType协议的任何类型)来从两个基础的序列中构建SequenceType 。 让我们分解一下。 SequenceType是一种协议,它允许类型使用for…in循环。 内置的收集类型是SequenceType的示例。 在下一级上, SequenceType协议定义了一个名为Generator (称为GeneratorType )的关联类型,该类型用于提供迭代功能以获得序列中的下一个Element 。 将所有这些放在一起,zip方法将创建一个对对序列,其中第i个对由每个基础序列处的索引值组成。 让我们举一个例子。 假设您有两个要相互关联的数组。 例如,您有一个学生姓名数组和一个与那些学生索引相匹配的成绩阵列。 如何创建一个将每个索引的学生和年级合并在一起的列表? 您猜对了,我们可以使用zip方法将它们组合在一起。 请参见下面的代码。 地图 每个SequenceType都有一个map方法,该方法将遍历其序列并在每个项目上调用传入的转换函数-收集结果并将其作为新数组返回。 使用map函数,可以将一种类型的数组转换为另一种类型的数组。 请参见下面的map方法签名: func map (@ noescape _ transform:(Self.Generator.Element)-> T)-> [T] 约束条件 Self:_CollectionWrapperType,Self.Index == Self.Base.Index 从前面的示例扩展,我们可以进一步格式化zip方法输出的结果以包括字母等级,并将结果转换为可通过其键访问的字典。 降低 reduce方法通过重复调用序列中的每个项目并传递一个Combine函数来累加值来返回单个结果。 func reduce (_初始:T,@noescape合并组合:(T,Self.Generator.Element)-> T)-> T 当您需要将数据点的集合煮沸成单个值时,reduce方法非常方便。 […]

使用UIGestureRecognizer对TableView单元格重新排序

最近,我有幸与一家创业公司的创始人通过咖啡见面,其中一位创始人提到了iPhone上的Weather应用程序。 具体来说,他提到了如何在应用程序中,用户可以重新排序他们对城市的偏好。 外观如下: 尽管这是一个小功能,但我知道这是我可以解决并进一步研究的东西,因为它真的使我对如何编写代码感兴趣。 有几种方法可以在项目中实现这一目标。 我发现了两种不同的方式,我将同时提及两种方式,但仅介绍我的首选方式。 第一种方法是更简便,更快捷的方法。 用户只需要首先运行一个简单的表视图并添加示例数据即可显示。 接下来,在情节提要中或以编程方式添加一个条形按钮项。 实现startEditing方法,然后取消注释canMoveRowAtIndexPath和moveRowAtIndexPath方法。 前者应返回true,而后者应用于对样本数组中的项目重新排序。 第二种方法是我更喜欢的方法,因为您无需实现编辑,并且可以在运行程序后立即重新排列表视图的顺序。 它涉及更多代码,但我认为这是值得的。 这是我采取的步骤。 我很幸运地在线找到了方法论(请参阅此处),并将其转换为Swift 3。 在您的tableview的viewDidLoad中,添加以下代码: let longpress = UILongPressGestureRecognizer(目标:自我,行动​​:#selector(TableViewController.longPressGestureRecognized(_ :))) tableView.addGestureRecognizer(longpress) 接下来创建您的longPressGestureRecognized函数: func longPressGestureRecognized(_手势识别器:UIGestureRecognizer){ } 在此函数内添加以下代码: 让longPress = gestureRecognizer为! UILongPressGestureRecognizer 让状态= longPress.state 让locationInView = longPress.location(in:tableView) 让indexPath = tableView.indexPathForRow(at:locationInView) struct My { 静态var cellSnapshot:UIView吗? =无 静态var cellIsAnimating:Bool = false 静态var cellNeedToShow:Bool = false } […]

我应该使用多少个测试?

我在开始撰写此博客时就对如何提高应用程序质量进行了解释。 在途中,我们遇到了许多不同类型的测试。 但是,我们应该对每种类型的应用程序投资多少? 一如既往,需要平衡。 这次是关于我们可以投资多少与将创造多少价值(不是总是这样)。 因此,让我们详细看一下。 单元测试 我们已经对单元测试进行了很多研究。 如何在Objective-C,Swift中做到这一点以及如何测试Apple的MVC(测试UIElements时不要忘记在UIViewController上调用controller.view)。 单元测试的优势是什么? 快速 可靠(如果操作正确;) 涵盖很多部分 具有所有优势,还有什么要错过的? 他们是孤立的 不要测试零件是否装配在一起 最重要的是他们要快。 不论是10还是1000,都没关系。它们在不到几秒钟的时间内运行。 开发人员没有理由在提交更改之前不运行它们。 这很简单。 我们拥有的越多越好。 这也是我们在TDD中使用它们的原因。 确保独立编写它们。 不要使用数据库或网络。 而是存根吧! UI测试 UI测试也是一个主题。 我们已经看到了多个框架来实现它们,以及如何使它们独立于任何后端。 优点: 测试组件 您可以将它们用于验收测试 它们的行为类似于用户 与往常一样,您可以期望它们有缺点: 慢 脆弱(对应用程序的每次更改都会破坏它们) 慢(我已经提到过吗?) UI测试需要大量维护。 它们可能会随时中断,即使只是由于模拟器无法连接到Xcode也是如此。 因此,它们显示的每一次失败,可能都不是您应用程序中的错误。 您需要对其进行调查。 最重要的是,它们运行非常缓慢。 即使当告诉他们不要在测试开始时重新启动应用程序,使用模拟后端并删除动画(您仍然不应该这样做)时,它们也会永远占用。 目前,我们的50个测试需要15分钟以上的时间才能运行。 每次更改后,没有开发人员会这样做。 因此,您的CI需要。 拥有它们真是太好了。 但是请注意,它们需要大量工作。 由于测试很慢,因此不应有比单元测试多的测试。 验收测试 我们已经研究了无UI的验收测试。 使用这种类型可以实现令人难以置信的目标。 他们甚至可以帮助您与客户合作并以更精确的方式确定需求(如果您想了解与客户合作的方式,请查看BDD)。 那么为什么要使用它们: 快速(与UI测试相比) 测试整合 […]

管理多个单元

斯威夫特3.0 在iOS中,通常在tableView中使用不同类的多个单元格。 由于我们的cellForRowAtIndexPath可能很快变得肿,所以这可能会变得很毛茸茸。 我已经看到开发人员直接使用indexpath确定要出队的单元。 对单元格的索引路径进行硬编码不仅使代码更难阅读,而且也使更改变得更加困难。 我发现的解决方案是使用cellList来管理所有这些。 将单元格限制为枚举 第一步是创建一个枚举,其中包含表视图可以出队的所有可能的单元格。 假设我们的tableView将显示有关使用3个单元格的人的信息。 一个AddressTableViewCell,EmailTableViewCell和PhoneTableViewCell。 然后,我们的枚举将包含三个值,如下所示: 列举PersonTableIndexPath { 案例地址 案例电子邮件 手机壳 } 这确保了我们的tableView仅能够使枚举中列出的单元格出队。 如果需要,还可以更新枚举以支持关联的值,但是此示例将保持简单。 使用单元格列表管理单元格 让cellList:[PersonTableIndexPath] = [.Address,.Email,.Phone] 我们的cellList本质上是一个枚举数组。 这样,我们将索引路径隐式链接到单元格类。 唯一的好处就是更改枚举在单元格中的位置List将直接与tableView中显示的索引路径相关。 如果已经正确处理了该cellForRow,则无需更改它。 在Table View的数据源中使用单元格列表 在numberOfRowsInSection中,一个衬线就足够了 返回cellList.count 在cellForRowAtIndexPath中,我们可以如下使用cellList: 让cellType = cellList [indexPath.row] 切换cellType { 案例。地址: 返回setupAddressTableViewCell(indexPath) 案例。电子邮件: 返回setupEmailTableViewCell(indexPath) 手机。 返回setupPhoneTableViewCell(indexPath) } 我们的设置方法将负责使单元出队,设置和返回。 由于开发人员确切知道单元格设置代码的位置,因此这使代码非常干净。 而且,cellList的魔力还没有结束。 如果我们将cellList更改为可变的,则可以在运行时更改枚举的顺序🙂 在运行时更新单元列表 如果我们需要添加另一个手机单元,我们要做的就是更新单元列表。 cellList.append(.Phone) tableView.reloadData() am! 真的是这样。 […]

2017年3月女性:将灵感转化为Swift3代码

在本月初,我有点编码狂。 也许那是在洛杉矶度假的两个星期,还有我每天都在吃的所有美味的玉米饼–但我无法忍受自己正在开发的应用程序。 直到月中旬,我(后来)对华盛顿的妇女游行有了更多的了解,我找到了灵感。 如果您不熟悉此活动,那么在华盛顿举行的女性游行就是一群妇女(或任何想代表自己的人!)在2017年1月21日,即特朗普就职后的第二天前往华盛顿游行。 得知此事件后,我立即查看了“女性游行”的网站,并计划前往哥伦比亚特区参加会议。 该网站干净整洁,内容丰富,但我注意到App Store中没有Women’s App应用。 虽然该网站提供了许多有关行军统一原则以及如何捐赠的信息,但它并没有太多的“一日”信息,例如行军路线,停车和浴室设施。 因此,有了新近掌握的编码技能,我开始为“女性游行”开发一个应用程序。 我制作的应用仅包含5个视图,并带有一个标签栏控制器以在它们之间进行导航。 我想制作一个简单,不太繁琐的应用程序,并且对于一次找到本地DC信息很有用。 对于主视图,我使用DarkSky API来获取每小时的直流温度和摘要更新。 完全公开:这些图片是从Women’s March网站上拍摄的,因此,房屋底部的小巧小字体是我赞扬他们的方式。 尽管游行不需要门票,但组织者要求人们报名参加此次活动,以便他们可以准确地计算人数。 在这里,我使用了webView来显示Google Form Women’s March注册页面。 我还提供了一个FAQ页面,其中包含我从官方网站和此Vogue文章中收集的一些信息。 在Tameika Lawrence的帮助下,它被构建为带有多个Q和A标签的scrollView 。 (谢谢你,Tameika!) 在我看来,该应用程序最重要的功能是mapView,其中包括以下位置:1)集合点2)跨性别友好的浴室和3)停车场。 对于浴室数据,我使用了Refuge Restroom API ,对于停车信息,我使用了Google Places API,并带有搜索词“ parking”和“ parkinggarage”。可爱的图标来自Icons8-我爱他们的图标! 最后,由于不熟悉DC Metro系统,我想提供一张地铁地图。 我找到了@wmata Metro地图,将其插入到imageView中,然后在该imageView中添加了一个捏合手势识别器 (以实现放大和缩小)。 这个程序花了我大约3天时间,制作起来真的很有趣。 我喜欢制作一个我知道人们(我)会觉得有用的应用程序。 不仅如此,我之所以工作很快,是因为我知道进军不到7天,需要尽快完成。 最终,女性游行在游行进行的五天前发布了他们的官方应用程序,因此我决定不将我的应用程序推送到App Store。 总体而言,我对自己开发的应用程序感到满意,并且很高兴能找到灵感的源泉。 最重要的是,我很高兴能够参加女子游行,并为这项运动做出了贡献。 我前进的原因有很多,但从未想象过我会经历到积极而充满希望的能量。 我离开了行军,感到鼓舞和动力来编写代码和构建程序,这些程序不仅很酷,而且可以改善人们的生活并将它们融合在一起。 在下面给我留言,告诉我是什么激发了您的代码。 您可以在这里找到我的仓库。

Swift中的闭包:续集

自从我开始学习Swift闭包以来,我发现自己实际上正在寻找它们,并尝试将它们更频繁地注入我的作品中。 我本着同样的精神涉足函数式编程 不可避免地 高阶函数 。 函数式编程已成为更高级的编程方法之一,它已成为摆在桌面上的一席之地。 但是,这与功能编程无关。 这是关于我对闭包的学习; 它们如何在高阶函数中使用,以及扩展后,它们在函数编程中的作用。 如果您尚未探索函数式编程,建议您这样做。 将您的🐽放到那里,看看是否喜欢它。 你知道他们在说什么,没有有害的知识。 本文主要借鉴了Ray Wanderlich的本教程,主要是因为我发现它很好地解释了并且阅读起来很有趣。 Ray Wanderlich的教程难道不是很棒吗? 🙌 要继续学习本章,您需要基本的闭包知识。 不是你的茶吗? 不用担心,当我的学习也不是我在这里喝茶的时候,我就写下自己的学习内容。 在进行函数编程之前,让我们回到舒适的区域。 这是我们最常使用的东西。 您有一个列表,想要遍历该列表并执行某些操作。 您将做什么,请召唤for循环! 这就是所谓的命令式编程 。 这看起来很整洁,您了解它并且很容易编写。 那么,为什么要解决未损坏的问题呢? 这就是为什么! 释放🐉,我的意思是声明性的! 上面的示例实际上只是一行代码,它很简洁,即使现在看起来不太像,但编写起来却容易得多。 这些只是我们看到的一些优势,我们将在进行过程中探讨其他更大的优势。 我有你的兴趣吗? 现在我们可以尝试定义什么是功能编程。 函数式编程是谁? 函数式编程是专注于数学计算并避免状态和可变数据的范例。 一旦避免了状态数据和可变数据,我们将转向高阶函数来填补空白。 与定义高阶函数一样,这似乎是一个好时机。 高阶函数 高阶函数是接受其他函数作为参数,可以返回一个函数或同时返回两者的函数。 当我们在这里探索闭包时,我们提到闭包被称为高阶函数functions。 上面有一个小问题,我们将使用它来查看几个高阶函数。 这是一个书店模型。 有各种组成部分的书籍和书籍清单。 地图 这是一个闭包 , 接受一个函数作为其参数,并在将函数应用于数组中的每个元素后返回 长度相同 的数组 。 问题1 我们希望在我们的小书店中获得所有书名的列表。 我们该怎么做呢? 势在必行? […]

我如何编写和发布Swift库以从Scratch下载数据

VolexDownloader为Swift 3 动机:😇 好吧,我一直很热衷于编写一段可以以某种方式帮助他人的代码。 我曾经写一些小应用程序来解决一些琐碎的问题,但是后来我决定写一个对其他开发人员而不是最终用户真正有用的低级API。 想法:💡 大多数应用程序的任务是以一种或另一种方式从Internet或Intranet下载数据。 每次都是同一段代码或创建一个请求,设置会话,创建任务,更不用说管理下载的内容了。 为什么不编写为您处理所有这些事情的一键式API,以便您可以专注于重要的事情,例如处理实际下载的数据。 它能做什么? 💪🏼 它具有以下模式: 使用用户界面: VeloxDownloader带有内置的下载视图,该视图显示下载进度,并且当前可以停止任何下载。 通过此API,您可以控制是否要为任何特定文件下载启用后台下载。 没有UI: 该API使用Swift闭包来返回下载进度,剩余时间和下载的完成状态。 您可以使用此信息来满足您的需求,甚至可以构建自己的下载进度GUI。 该API还允许您为任何特定文件下载启用或禁用后台下载。 设计与代号:🙇🏼 好吧,我在网上环顾四周,并从现有的图书馆中获得了一些动力。 它们要么是用Obj-c编写的,要么仅提供了一个特定的用例。 我想结合所有这些实现,以提供您只需调用的多合一产品即可为您完成工作。 在这种情况下,您只需给它提供文件url,然后它将在特定位置为您下载。 我首先考虑了文件的生命周期。 有关持久性和删除下载文件的设计决策。 库检查temp和应用程序缓存目录中的命名冲突,并相应地删除和/或覆盖。 接下来考虑的是下载以及开发人员选择的各种模式。 实例化了URLSession并根据下载的前台与后台进行了正确的配置。 完成上述设置后,在Xcode控制台上的日志中产生了正确的结果后,我继续使用UI并创建了自定义tableView来显示下载活动。 我选择为此创建xib,因为我知道将来必须将其作为库发布。 为单元格创建了一个xib,为tableView本身创建了一个xib。 然后是将下载逻辑链接到我各自的视图控制器的任务。 好吧,长话短说,我使用协议和通知来实现这一目标。 我的下载程序类发布了有关通过协议和通知下载的文件状态的更新,我的UI类根据下载开始,完成或被用户停止更改了UI组件。 Github🐙 我创建了所有源代码并将其提交到Github中。 我以前从未以库的形式发布过它,所以我不得不重新格式化我的项目结构。 我将所有文件(.swift和.xib)合并在一起,这些文件将成为我的库的一部分。 你可以在这里查看 我创建了一个问题,将所有提供我链接的媒体插入到我的项目自述文件中以显示gif和图片。 一旦我认为我的实现成功,就从开发分支创建了一个pull请求,将所有更改合并到master中。 我通过克隆项目并运行它进行了快速检查。 中提琴,一切似乎都正常。 此时,我创建了一个发行版,并为其指定了版本号。 椰子足🍫 这很容易成为整个旅程中最困难的部分。 部分原因是因为我以前没有发布过Pod,但从中学到了很多。 以下是重要的痛点: 创建一个podspec文件。 这是Pod脚本读取的文件,以了解有关项目的所有信息。 它由您的项目在github上的位置,在cocoapods.org上创建相应的pod版本的版本号,源文件所在的位置,源文件的扩展名等组成。 我只需要假设Cocoapods.org上提供的详细信息对于像我这样的初学者来说就足够了,但是如果需要像我这样的人,我仍然会继续详细介绍整个过程。 确保您的系统上安装了cocoapod。 如果您不确定,请按照以下步骤开始操作。 […]