上一次,我们做了很多设置以开始使用Amazon Web Services的DynamoDB ,包括使用Swift-Python桥,以便我们可以使用官方的AWS接口boto3与DynamoDB进行通信。 但是boto3除了基于Python并因此没有Swift类型安全性之外,还具有一些局限性:它很复杂,难以使用—并且存在同步的主要问题。 要查看该问题,请运行上次到达的代码: …现在,请尝试关闭计算机的WiFi ,然后重新运行。 怎么了? table.scan()行仅挂起那里30秒钟,直到出现令人讨厌的异常并且程序崩溃(带有不可恢复的致命错误)。 实际上,这不是我们希望库调用或可能具有间歇性网络连接的应用程序(例如移动应用程序¹)所期望的行为。 本文-更好的boto Dyno库旨在做得更好。在本文中,我们将介绍如何做! 和以前一样,尽管这个想法是产生一个有用的库,但我也希望展示可以在自己的代码中使用的技术。 我们将使boto3调用异步。 这将演示信号量,工作队列和工作项的使用 Dyno将利用新的Swift 5 Result类型发布一个Observable结果流。 在这里,我们将演示带有复杂数据流的Observable和Reactive编程 我们将添加一些有用的,类型安全的方法来从DynamoDb(原生于Swift)读取和写入数据。 这说明了 我们数据类型上的 一些出色的功能构造,例如 zip 和 flatMap 在本文的最后,我们将直接从Swift将Dinosaurs(当然是🦕和))写到DynamoDB数据库中,然后以异步方式读回它们,并适当考虑网络延迟。 这将成为我们Dyno库的开始。 和以前一样,该库正在公开开发中,因此您可以在github( swiftify分支)上查看源代码。 有很多事情要做,让我们开始吧! 可观察的流 正如我在上一篇文章中提到的,可观察对象是表示数据流的一种方式。 我们可以将它们连接到Reactive组件,以便能够以功能强大和声明性的方式处理数据流。 这是表示数据操作的一种非常强大的方法-我们将在以后的文章中介绍,但是现在我们将看看如何将DynamoDB交互表示为Observable。 建模数据交互的关键是要注意它们都看起来像这样: 要求DynamoDB做某事(扫描表,更新行等) 等待结果(返回200行,更新成功)… 或出现错误,例如 超时或数据完整性错误。 我们使用DynoActivity数据类型的可观察流对这些阶段进行DynoActivity : 它就像一串可观察的事物(橙色和红色的大理石代表可观察的事件)看起来像这样: 现在,我们要做的一件事是假设即使一次大型查询(例如,返回了数百行),我们也一次性获得了所有数据:我们不对输出进行“分页”。 我们将来可能会改变它²。 您可能还会注意到,我们希望我们的可观察流以多线程的方式异步工作:我们可以让多个流同时运行,有的读取数据,有的写入。 为什么我们不将Future用于这种类型的异步数据请求/响应? 使用Observable流可以非常轻松地处理诸如“显示等待图标,直到返回数据或显示错误”之类的交互模式。 对于实际应用而言,这是非常基本的。 现实检查 在创建高级Observable之前,我们需要处理以下事实:通过不可靠的连接与远程数据库进行同步接口,并使用Python接口进行引导。 具体来说,我们需要确保Dyno正在控制AWS连接上的活动,而不是将其留给Boto3的30秒同步,程序终止超时。 那么,如何在不自行控制Boto3代码的情况下使Boto3异步和多线程呢? 我们将使用DispatchSemaphores […]
大部分时间都可以坐下来编码。 该死的,我没有抓住机会。 发现到目前为止,我想要在此应用程序中实现的所有功能绝对引人入胜,我能够毫无问题地实现。 猜猜通过树屋之类的网站了解核心概念的所有时间已经开始得到回报。 学会UIAlertController到几乎流利的程度,集成了UIImagePickerController,学会了如何将DatePicker集成到UITextfield中。 然后最重要的是,我成功地将所有这些不同数据类型的状态存储到我的自定义EventData结构中,然后成功地打印回了我想要的值! 还集成了受密码保护的UITableViewCell,我真的很惊讶通过谷歌搜索/调整代码来实现这一点。 现在,我遇到的主要问题是:将自定义DataType保存到某种持久性存储中。 我以为可以将其存储在UserDefaults中,但是出现的错误使我想到可能必须使用其他工具才能获得此结果。 将我的问题提交给iOSProgramming子reddit,我们希望对此有解决方案!
如果您像我一样,每当您“被迫”向您的应用添加第三方灾难二进制代码时,它都会给您带来沉重的负担。 当客户想要添加“分析”时,我通常会遇到这类库。 我遇到最多的是Google Analytics(分析)。 这是一个相对简单易用的好工具。 它已经存在了几乎永远,因此被广泛传播并广为人知。 不幸的是,就像大多数其他针对iOS的分析解决方案一样,闭源二进制代码😱。 这有几个原因使我误解了。 我无法查看代码。 我真的不喜欢没有选择了解我构建的应用程序中包含的代码的选项。 当代码旨在跟踪,衡量和报告用户行为时,甚至更是如此。 这些事情通常以我认为“令人毛骨悚然”的方式完成。 我们都记得Twitter是如何使用canOpenURL找出用户在iPhone😒上安装了哪些应用程序的。 我非常相信销售广告的每个人(包括Google)都采取类似或“爬行”的策略。 las,这是您使用广告销售公司的分析解决方案时必须面对的问题。 现在大部分 Google Analytics(分析)在后台使用了称为Google Measurement Protocol的工具。 这是一个完全开放且有文档证明的API,任何人都可以向其发送请求。 它使我们能够建立自己的报告机制,以将数据提供给Google Analytics(分析)👍。 我已经围绕该API构建了一个不错的小包装,使将基本的Google Analytics(分析)轻松运送到我为客户构建的所有应用中。 您可以根据需要使用它,也可以简单地构建自己的🤓。 只花了约150行Swift代码。 使用我的GoogleReporter实现,可以轻松跟踪事件,屏幕浏览和异常。 跟踪屏幕视图的方法如下: 类BeerViewController:UIViewController { 覆盖func viewDidAppear(_动画:布尔){ super.viewDidAppear(动画) GoogleReporter.shared.screenView(“啤酒”) } } 或一个简单的事件 func didCompleteSignUp(){ GoogleReporter.shared .event(“ Authentication”,操作:“ Signed Up”) } 在开始之前,您需要做的就是为跟踪器配置添加新应用程序时Google Analytics(分析)吐出的属性ID。 GoogleReporter.shared.configure(withTrackerId:“ UA-XXXXX-XX”) 如果您正在考虑向应用程序添加Google Analytics(分析)支持,则应在GitHub上查看GoogleReporter。
在下载管理器框架的Swift 4迁移过程中,我重写了模型对象(符合NSCoding NSObject子类)。 我的DownloadItem的状态由带有关联值的枚举表示: 使用Swift 3,我必须编写一个符合NSCoding的包装对象,以保留该枚举。 使用Codable不再需要此解决方法,因为我可以直接向枚举添加Codable一致性。 现在,有不同的方法可以实现此目的。 我仍然不确定最好的解决方案是什么,但是也许有人可以使用我目前的方法。 在查看DownloadState ,让我们看一下一个简单的Value枚举示例: 在类型和大小写之间存在一对一的映射,因此我们可以设置一个如下所示的容器: //伪字典 [“ string”:字符串,“ int”:Int,“ data”:数据,“ double”:Double] 毕竟, KeyedDecodingContainer和KeyedEncodingContainer只是非常严格的字典,其中下标键是强类型的String枚举(符合CodingKey ),而getter和setter利用Swift的错误处理系统来提供有意义的错误,说明为什么获取或设置特定键的值可能失败。 因此,至少对我而言,将容器视为具有固定键的字典是有意义的🙂 为Value实现Codable可能看起来像这样: 我们使用decodeIfPresent函数,因为将只设置一个密钥。 缺点是我们不使用switch语句进行解码,因此当我们添加新的大小写而忘记对其进行解码时,编译器不会对我们大喊大叫。 而且,它不适用于DownloadState示例,因为我们有带有和不带有关联值的案例。 我的方法是使用“基本”案例和关联值作为CodingKey ,然后让一个私有枚举将所有基本案例作为简单String托管。 让我们看看它的外观: 我真正喜欢的是编译器可以完全自动生成Base的Codable实现,因为它只是一个String枚举。 不幸的是,我们仍然必须为DownloadState provide提供Codable实现。 以下伪字典都是DownloadState所有有效表示形式。 //伪字典 [“基地”:“取消”] ->下载状态。取消 [“ base”:“ paused”,“ pausedReason”:“ waitingForWifi”] -> DownloadState.paused(原因:.waitingForWifi) [“基础”:“下载”,“下载进度”:0.5] -> DownloadState.downloading(进度:0.5] 可以缩放吗? 不……如果涉及多个关联值,则实际上这是一个非常复杂的类型,应像嵌套结构或类一样进行处理。 请考虑以下示例,其中Route表示带有主页和详细信息页面(用于播放音乐)的音乐应用程序的不同屏幕: 超级简单吧? 但是将每个关联的值添加到CodingKeys 有一些缺点: 在与基本情况相同的层次结构上具有关联值在语义上是错误的(就像在DownloadState示例中一样,但是更加突出) 如果枚举得到更多的情况(和更多的关联值),这将变得更加难以阅读和维护 如果这是一个类或结构,则您永远不会考虑对父代中嵌套类型的信息进行编码。 […]
快速编程基础知识和功能入门,可以快速地在地图上显示相互间的联系 ,包括Map , flatMap , reduce , filter , foreach … Dans cet文章,nous nousintéresseronsseulement aux fuctions map和flatMap 。 禁止在任何其他场合使用的功能。 Elles Sont utiles倒向了manipuler les collections和les type optionnels。 地图 Vous pouvez utiliser la fuction map pour boucler une collection et appliquer lamêmeopérationàchaqueélémentde la collection。 Voici签名: 功能和性功能清单,以及功能清单。 Cette函数转换为ValerDonnée和Valet Valeur(pasforcémentdumême类型)。 Voici un cas d’utilisation de la fuction map : […]
工具:安全矩阵协议和类型 您可以决定事先浏览SafeMatrix.swift代码,或者直接跳到下面的“设置和使用”部分。 设置第一部分:现有矩阵实现 正如我在一开始所解释的,我们需要从现有的矩阵库开始。 我的Matrix结构示例实现 以下内容包括初始化,条目查找,可变条目,加法,乘法和标量乘法。 在此实现中,条目的类型为Double ,但它们可以为Int或任何其他类型。 此实现缺少转置,行列式,逆和许多其他标准矩阵运算。 设置第二部分:数字 在以下各节中,我们将初始化和操作SafeMatrix泛型结构的实例。 此结构具有三种关联的类型; MatrixType ,符合UnsafeMatrixProtocol 行 ,符合NumeralProtocol 符合NumeralProtocol的 列 您可能已经猜到了, MatrixType将成为我们的“现有” Matrix类型。 那么什么是行和列 ? 这些类型的唯一目的是提供专用SafeMatrix结构的行数和列数。 这样,除其他事项外,具有不同维度的两个矩阵始终是不同类型的。 在我们的示例中,我们假设我们有两个全局变量m和n , 并且我们的代码将具有m×n , n×m , m×m和n×n矩阵。 在实际的用例中,您可能需要从外部源(例如文件或Web服务)中加载这些值。 我不在这里考虑这些情况,但是可以通过修改设置来解决。 用法第一部分:初始化 我终于准备向您展示生成的m×n安全矩阵类型。 这只是SafeMatrix ,并且可以使用m×n Matrix进行初始化。 使用第二部分:运算符 回想一下,我们的Matrix类型支持加法,乘法和标量乘法运算符。 我们想将它们移植到SafeMatrix 。 为此,我们再次需要编辑MatrixSetup.swift : 使用第三部分:转置,逆和行列式 在本节中,我们假设Matrix类型包含transpose , inverse和determinant方法的实现。 现在,我们在Matrix.swift中添加了存根实现,但是要注意,您将需要真正的实现才能使usageMethods()函数运行。 如果您觉得本文有用或有趣,请推荐💚并考虑加入下面的讨论🙂!
当我第一次听到它时,我承认这听起来很奇怪。 一个聪明的同事向我提出了建议,我想:“这肯定是在浪费时间,因为Xcode为我提供了许多便利”,“为什么要增加项目的复杂性?”我想到了其他问题。 。 后来,我学习了更多的主题,并且对软件体系结构产生了兴趣,因此我意识到这些Xcode设施需要付费。 在这段时间里,当我考虑这个话题时,我受Facebook邀请参加了招聘过程,虽然我没有被录用,但是我发现Instagram团队不使用故事板,至少面试官告诉我那。 我想知道他们为什么要这样做吗? 他们是Facebook公司,当然有充分的理由。 您使用情节提要的优势显而易见,我们无需多说。 另一方面,您所支付的价格并不比情节提要设施亮。 在这里,我将提出这种方法的一些优点,我的意思是说,以编程方式进行布局,并且我将共享一个简单,快速的项目,因为您对它的开发方式有所了解。 我的建议是,查看每个类的行数,查看责任分配方式,查看依赖注入的角度等等。 花更多的时间进行开发; 有时,组织团队协作可能会更复杂; 为了更加灵活地注入依赖关系,您必须创建类初始化程序,并定义如何将其作为视图控制器的输入参数。 我更容易跟踪代码上的更改,我的意思是,代码比情节提要XML文件更具描述性; 解耦并使其可测试非常好,并且谈论去耦,您可以创建主视图,从视图控制器中取出演示逻辑,而情节提要板很难做到。 总结关注点分离; 我的意思是,更易于制造可重复使用的组件,您需要以这种方式进行思考; 很棒的风格和简码; 有机会更好地了解事物在幕后如何工作,UIKit,约束等; 我花了一些时间才意识到优点和缺点。 你怎么看? 请在这里发表评论。 别忘了看下面的示例,再见,下次见。 启发式/螺旋 screex –以编程方式布局示例 github.com
在过去的几个月中,我很高兴能够开发tvOS应用程序。 针对tvOS的开发与iOS非常相似,这使得从一开始就可以很轻松地进行工作。 在对其中一项功能进行多次迭代之后,我们偶然发现了其中一种集合视图带来的性能下降。 在Instruments上花费的时间揭示了我们可以应用的许多潜在优化,其中包括为我们的集合视图缓存布局属性,对我们的滚动算法进行进一步的优化等。所有优化为除了一个不需要的集合视图之外的所有内容都提供了出色的结果表现良好。 除了一个集合视图外,其他所有内容均以惊人的60 fps速度运行。 这很快就变成了我的爪子上的荆棘,我开始执行一项任务以弄清为什么会发生这种情况。 我没有指望单击Xcode中的“配置文件”按钮的次数。 我开始剥离UI元素,更深入地了解配置文件堆栈,最后我在针对tvOS优化的黑色犯罪故事中遇到了一个嫌疑犯。 所有证据都表明, UIProgressView是罪魁祸首。 现在我们终于发现了一个很大的弊端,是时候该弄清楚如何解决这个问题了。 但是在我们进入解决方案之前,我想提出一个我的理论来说明为什么会这样。 因为我不知道UIProgressView的内部工作原理,所以我无法将我的理论作为事实提出来,但是如果您继续研究,我认为您会同意这是有道理的。 我最初认为这是Apple的错误,并且打算提出警告,但是经过更多的考虑,这更多的是Apple提供的实现成本,这使我们不适合在这种情况下使用。 话虽如此,我们没有在新的Apple TV上看到相同类型的帧丢失,这意味着随着时间的流逝,此问题将自行解决。 我们不能只是坐下来等我们的用户升级硬件,因此我们推出了自己的解决方案,该解决方案将更适合我们的需求,并以我们想要的方式扩展。 由于UIProgressView旨在在尽可能多的情况下工作,因此Apple选择了UIVisualEffectView 。 我知道这个选择; 不幸的是,如上所述,这并不能很好地扩展,因为我们一次显示了十到十一个视图,所有视图都使用了此实现。 根据设备的不同,它可以使帧丢失达到20 fps或更高。 另外,我们的设计不必依赖UIVisualEffectView,因为我们添加了渐变以确保进度视图始终对用户可见。 您可以说Apple提供的原始实现针对我们的用例进行了过度设计。 可能还有其他原因导致它对我们而言效果不佳,我们用来解决该问题的解决方案是制作自己的进度视图版本,该版本不受UIVisualEffectView的支持。 因为我们希望它可以替代UIProgressView ,所以从UIProgressView复制了公共API。 它使开始使用视图变得更加容易,因为我们只需要更改要使用的类即可,而不必更新对该类进行的所有方法调用。 我们的替代产品包括两个CALayer ,一个外层代表总进度,另一个内层代表当前进度。 外层的拐角半径等于进度视图高度的一半; 这使它具有与UIProgressView相同的形状。 对于动画,当我们调用setProgress(_ progress:Float, animation :Bool = false)时,我们将提供一个CABasicAnimation ,并将其添加到内层。 由于CALayer缺乏使用约束的能力,因此将图层和动画包裹在常规的UIView中 ,使其更易于使用。 将这个新的进度视图放入我们的应用程序后,我们的应用程序再次开始达到60 fps,用户获得了他们应有的性能。
斯威夫特4,Xcode 9 如果您需要创建一个可以从一开始无限向左或向右滚动的收藏夹视图,那么这里就是正确的地方! 我为模型使用了简单的颜色阵列 懒惰的var colorList:[UIColor] = { var colors = [UIColor]() 步调为(从0到1.0:0.25){ 设color = UIColor(hue:CGFloat(hue), 饱和度:1 亮度:1 阿尔法:1) colors.append(颜色) } 返回颜色 }() 现在,让我们遵循那些collectionview协议。 注意,colorList只是使用%运算符包装了它的数据 func collectionView(_ collectionView:UICollectionView,cellForItemAt indexPath:IndexPath)-> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier:“ ColorCell”,for:indexPath) cell.backgroundColor = colorList [indexPath.row%colorList.count] 返回单元 } numberOfItemsInSection可以通过使用大常量来解决。 用户需要滚动数月才能到达终点 让infiniteSize = 10000000 func collectionView(_ collectionView:UICollectionView,numberOfItemsInSection部分:Int)-> Int { 返回infiniteSize } 通常只要初始化collectionview,用户就不能向左滚动,因为它是第一个索引路径。 […]
我想要的只是状态栏的两件事: 我希望它默认为白色,因为它会在深色背景上 我希望能够不时地暂时隐藏它。 直截了当吧? 没那么多……让我们看一下这个案例。 因此,如果您四处逛逛,有几种方法可以操纵状态栏,让我们看一下: 在“常规”选项卡中,您可以找到用于项目目标的首选项的两个字段,这些字段用于调整状态栏的默认行为: 状态栏样式-在浅色 (即浅色文本)或默认值 (即深色文本)之间选择 隐藏状态栏-一个复选框。 这些字段是从info plist派生的,这是调整这些字段的另一种方法: 如果您使用info.plist来调整状态栏的默认行为,则需要为以下行添加行: 状态栏最初是隐藏的 ( UIStatusBarHidden ) 选择是或否 。 状态栏样式 ( UIStatusBarStyle )。 从以下任一选项中进行选择: 默认 ( UIStatusBarStyleDefault ) 轻 ( UIStatusBarStyleLightContent ) 忽略Xcode希望您在不透明黑色样式和透明黑色样式(alpha值为0.5)之间进行选择。 这些是不推荐使用的样式,似乎没有人告诉过属性列表编辑器! 如果仔细观察,您会注意到我在info.plist中设置了另一条与状态栏相关的行-另一个名为基于视图控制器的状态栏外观的布尔属性-我将在稍后再讨论这一行。 因此,它们是为状态栏样式设置默认值以及是否将其隐藏的方法。 但是,如果您要临时更改这些默认值,该怎么办? 如果环顾互联网,您会看到提到的两个替代解决方案: 在UIAppDelegate上设置属性 覆盖视图控制器类中的属性 有些人会建议您在UIAppDelegate上设置属性: UIApplication.shared.statusBarStyle = .default //设置样式UIApplication.shared.isStatusBarHidden = false //如果隐藏则设置 例如,可以在应用程序的UIAppDelegate的didFinishLaunchingWithOptions方法中或在您真正喜欢的任何地方进行设置(例如,如果要临时更改视图控制器的设置,则可以在viewDidAppear和viewDidDisappear方法中进行viewDidDisappear 。 听起来不错,对吧? 只需调用一种方法即可更新状态栏,非常简单。 哦,等等,对不起。 我忘了提一下-iOS […]