Tag: Swift编程

使用Swift设计多线程应用程序

作为汽车行业的iOS开发人员,我花了大量时间处理实时数据。 在当今的许多应用中,有效处理连续数据流的需求非常重要。 为确保不锁定用户界面,您很可能需要使用多线程。 实时流式传输的信息最有趣,因为您将不断收到可用于更新视觉效果的新数据。 这也是您最困难,最令人沮丧的事情,因为iOS设备在硬件方面有一定的局限性。 幸运的是,Apple通过称为GCD(大中央调度)的极其易于使用的界面提供了多线程。 您可能熟悉看起来像这样的代码: 如果您没有将主程序代码显式放置在另一个队列中,那么它将在其中运行大多数程序代码。 这是一个串行队列,这意味着它将选择行中的第一个项目,执行代码,等待它完成,然后释放该项目,然后选择行中的下一个项目,依此类推。 但是,主队列并不是通过GCD可用的唯一队列。 有许多预定义的队列都具有不同的优先级。 您还可以通过以下方式创建自己的专用队列: 请注意,我们刚刚创建的队列具有.concurrent属性,这意味着该特定队列在执行下一项之前不会等待一项完成。 它将简单地将第一个项目放在线程中并启动它,然后继续进行下一个项目,而不管第一个项目是否完成。 假设您正在处理采样率约为20Hz的数据流。 这意味着您将有大约50毫秒的时间来解析和解释数据,将其添加到数据结构中,并告诉视图进行显示。 如果您的iOS设备尝试在主线程上执行此操作,则将几乎没有时间检查用户是否尝试与该应用程序进行交互,并且您的应用程序将变得无响应。 这就是我们转向多线程的地方。 假设我们使用一个非常简单的数据结构来存储我们收到的数据样本,即一个普通的整数数组。 我们可能很想创建一个队列并像这样使用它: 看起来不错吧? 现在,我们正在后台线程上进行所有数据处理,而主线程仅用于更新视觉效果。 但是,这势必会崩溃。 但为什么? 答案有点技术性,但是考虑这一点很重要。 由于我们的队列是并发的,因此它将在线程上抛出要并行执行的工作项。 我们还将数组用作数据存储。 Swift数组是一种结构类型,这意味着它是一个值类型。 当您尝试将值附加到这样的数组时,您将: 分配一个新数组并复制旧数组中的值 追加新数据 将新引用写回您的变量 系统继续释放旧阵列使用的内存 想想如果两个线程将相同的数组复制到它们,然后将自己的数据附加到副本,然后将新的引用写回到我们的变量(一个在另一个之前,或者两个在同一时间)会发生什么。 第一种情况会给我们不正确的数据,因为首先写入的线程所写的数组中会丢失首先写入的线程中的数据。 第二种情况将导致我们的应用程序崩溃,因为两个线程无法同时获得对分配的内存的写访问权限。 考虑到这一点,我们可以使用DispatchQueue类附带的非常聪明的构造,即标志。 现在,我们可以像这样更改代码: 这看起来令人生畏,但我将解释它的作用。 每当添加一个将通过写入而更改数据结构的项目时,通过使用.barrier标志,我们告诉队列该特定工作项将需要自己执行。 这意味着队列将需要等待所有正在运行的线程完成,然后运行该项目并等待其完成,然后它才能再次开始并行执行代码。 当主线程需要访问数据以更新我们的视图时,它需要通过同步调用来遍历数据队列。 如果不这样做,则存在我们编写线程之一随时损坏其正在读取的数据的风​​险。 希望您能成功并从中获得一些新知识。 几天后重新阅读一遍可能会有所帮助,让自己有机会进行反思。 如果您有任何疑问,请随时发表评论,然后继续获取有关未来文章的通知。 要了解有关iOS开发的更多信息,可以查看我以前的文章: iOS开发和错误的MVC类型 作为iOS开发人员开始时,您会听到很多有关MVC(模型-视图-控制器)模式及其状态的信息。 medium.com

斯威夫特&&愤怒。 设置控制器。

4.将方法添加到SettingsViewController。 覆盖 func tableView( _ tableView:UITableView,didSelectRowAt indexPath:IndexPath){} 5.接下来,我们将添加一些依赖于indexPath的操作 覆盖 func tableView( _ tableView:UITableView,didSelectRowAt indexPath:IndexPath){ 如果 indexPath.row == 1 { } 如果 indexPath.row == 2 {} } 6.首先,行动将是与我们联系。 就我而言,它将打开Instagram。 如果 让 url = URL(字符串:“ https://www.instagram.com/curlnomad/”){ UIApplication.shared.open(URL,选项:[:]) } 7.接下来,我们将添加没有动作的简单AlertController 让 alertController = UIAlertController(标题:“”,消息:“确定要注销”,preferredStyle:.alert) let action1 = UIAlertAction(标题:“是”,样式:.default) 让 action2 = UIAlertAction(标题:“取消”,样式:.cancel) alertController.addAction(action1) alertController.addAction(action2) self .present(alertController,动画: true ,完成: […]

在Swift中使用Clean Architecture的外部依赖关系

与你们中的许多人一样,我们一直在为GDPR做最后的冲刺。 而且我们意识到我们的应用程序与外部SDK有很多依赖关系 。 市场营销需要新的跟踪, 导入SDK-A 。 我们需要深度链接, 导入SDK-B ,我们还需要跟踪广告, 导入SDK-C ,有关应用程序通知的信息… SDK-D … 🐞问题 所有这些花哨的SDK给我们带来了很多问题 您见过这样的AppDelegate吗? func appDidFinishLaunching … { Firebase.setup(“ 32FD-324AFF-12FD4D”) Firebase.logLevel = .verbose AnotherSDK.start() AnotherSDK.startSomething() AnotherSDK.disableSomething() AndAnotherSDK.doAnotherConfiguration() 返回真 } 如果我们有一个新的Swift版本,我们需要等到所有这些SDK更新之后。 使用Cocoapods时,干净的编译可能会花费很长的时间,因为我们需要重新编译所有这些漂亮的依赖项。 我们决定使用SDK-A,在没有真正注意到的情况下,我们50%的类都在使用SDK-A的API。 如果SDK-A的所有者决定关闭此漂亮的工具怎么办? 它还将关闭我们的应用程序! 我们都是这些SDK的奴隶! 更有趣的是:使用GDPR,用户必须控制所有这些SDK。 等一下,不要和市场营销人员打架! 🏆清洁建筑 是时候为这些混乱带来一些秩序了。 外部依赖项需要成为我们应用程序的插件! 应用程序使用Crashlytics,Appsee,控制台报告崩溃,将其存储在文件中或将其打印在纸上并不重要 。 这些只是细节。 💉依赖注入 因此,让我们开始构建一个我们可以注入的协议(因此可以在单元测试中对其进行模拟。) ⚙️模块 请务必注意, 唯一的公共API必须是ExtenalDependenciesInjection。 因此,我们可以将整个实现带到另一个模块中。 之后,我们可以将该模块导入到我们的应用中。 甚至在许多应用程序中重复使用此模块。 因此,我们不必经常重新编译所有这些外部依赖项。 您的编译时间将更快,CI服务器也会更快。 […]

如何使用弱引用和无主引用来中断引用周期?

#第二种情况 当一个属性被允许为nil而另一个属性不能为nil 。 在这种情况下,无主引用最适合打破潜在的强引用周期。 什么是无人参考? 例如,使用未拥有的引用的生存 期比其他实例更长或更长 。 这意味着引用为“无主”的实例将始终具有值,因此始终将其声明为非可选的。 ARC永远不会将无主引用设置为nil,即使其引用的对象已释放。 因此,您应确保不要释放未拥有的引用,否则,如果尝试访问它,则会导致运行时错误。 例: 让我们考虑一个客户和BankAccount的示例。 在这里,Customer和BankAccount之间的关系与Person and Appartment示例略有不同。 客户可能有也可能没有银行帐户,但银行帐户将始终与客户关联。 让我们看看这将如何导致潜在的强参考周期。 客户类别{ 命名:字符串 var account:BankAccount? init(name:String){ self.name =名称 } deinit {print(“ \(name)正在被初始化”)} } Class BankAccount { 让号:UInt64 让客户:客户 init(数字:UInt64,客户:客户){ self.number =数字 self.customer =客户 } deinit { 打印(“正在取消初始化具有帐号\(number)的BankAccount”) } } 如您在上面的代码中所看到的,我们已经在BankAccount类中将客户属性设置为常量或非可选,因为我们知道银行帐户在客户中将始终具有客户和可选帐户属性,因为客户可能拥有或可能没有银行帐户。 var harry:客户? 哈里=客户(名称:“哈里”) harry?.account = BankAccount(号码:1323243214214,客户:哈里!) 哈里=零 如果运行上面的代码,则不会看到任何deinit方法被调用。 […]

使用GCD在iOS中进行多任务处理

多任务处理使我们可以同时运行许多任务。 GCD(Grand Central Dispatch)是在iOS中实现多任务处理的最简单方法。 我们将任务添加到调度队列,这些任务又在多个线程上同时执行。 我们可以在后台线程上执行诸如下载或搜索之类的耗时任务,这将使UI响应用户。 iOS提供了用于在后台线程上执行任务的全局调度队列,以及用于在main / UI线程上执行任务的主调度队列。 我们还可以创建自己的任务执行队列。 let queue = DispatchQueue(标签:“ com.gcd.simpleQueue”) 我们需要为队列提供唯一的标签。 它可以是任何字符串,但是约定是使用反向域名(反向DNS)。 要执行任务,我们必须将其称为.async或.sync 方法。 任务不过是要执行的代码块。 queue.async { _ in 1…5 { 打印(“ clap..clap..👏”) } } 输出: 拍手..拍手..👏 拍手..拍手..👏 拍手..拍手..👏 拍手..拍手..👏 拍手..拍手..👏 调度队列上的.async和.sync方法告诉系统如何执行任务。 让我们用下面给出的示例进行检查。 func executeSync(){ 让队列= DispatchQueue(label:“ com.gcd.simpleQueue”) print(“ Start Race:”) //在同步模式下在队列上运行 queue.sync { 因为我在0 .. <5 { print(“ 🐢 […]

2017年以来我所有的副项目

去年,我为朋友和家人进行了许多附带项目和小型自由演出,以期在各种不同平台上磨练我的软件开发技能。 2017年5月,我被Raizlabs聘为软件工程实习生,当时我认为这将是iOS开发,但最终以Android为主。 我在Raizlabs的夏天很棒。 我必须出去玩,向一些非常聪明的人学习,作为办公室里唯一的实习生,当我遇到任何一种障碍物时,每个人都渴望帮助我。 我有机会与RZ团队一起开发了一些出色的应用程序,但我想清楚一点,以下所列项目均与Raizlabs没有任何关系,它们完全是我自己的。 我目前是缅因州不伦瑞克市Bowdoin学院的一名大四学生,在那里我为棒球队打DH / LF。 成为Bowdoin棒球队的一员不仅意味着要穿球衣并在网站上列出,还意味着更多。 加入团队意味着您是一群紧绷的人的一部分,这些人不仅存在于花名册中,而且延伸到一大批校友中。 去年秋天,两位刚毕业的棒球运动员联系了我,他们的想法是建立一个网站,让Bowdoin棒球队的校友相互交流。 存在类似的网站,但他们希望此网站仅适合我们团队的当前球员和校友。 我在Ruby on Rails中构建了该网站的第一个版本,并将Firebase用于数据存储和身份验证。 RoR Bowdoin棒球校友网站的第一版 那年秋天,我参加了Eric Chown教授的移动计算课程,该课程本质上是16周的iOS编程训练营。 对于我们的最终项目,我们的任务是提出一个应用程序创意并生成一个可行的原型。 我选择构建Bowdoin棒球校友网络的移动版本。 不幸的是,校友网络周围的嗡嗡声消失了,因为负责运行该校友的两个校友都忙于继续他们的营销工作,所以我从未将应用程序放在商店中,而是保留了代码库,并准备在校友获得时进行部署再次感兴趣! Raizlabs的文化基础是Hack Days。 RZ遵循Google的80/20规则(可能不再存在,在线上有许多相互矛盾的报告)采用,它鼓励公司的每个人在每两周冲刺结束时参加一次“黑客日”。 Hack Days提供了进行个人项目,研究新想法或测试您感兴趣的技术的机会。 这篇博客文章中的几个项目都来自Hack Days。 CFGLive是我在RZ的第一个Hack Day项目。 在我的第一次正式冲刺结束后,我从导师那里收到了一则消息,内容是:“不要碰积压! 今天是您的Hack Day!” CFGLive的想法是将FanDuel / Draft Kings日常幻想模型应用于计划于8月第一周(此黑客日为2017年6月16日)的Crossfit Games。 该应用程序的工作方式如下:用户将创建一个帐户,然后提示他们选择前十名的男性完成者,并为其选择命名,即“ Sawyer’s Super Picks”。提交前十名的男性后,系统将提示他们选择十名女性,然后是5支队伍。 有关Crossfit游戏如何工作的详细信息,请阅读此内容。 到一天结束时(我大概在晚上7:30才离开办公室,因为我被超级带走了),我完成了所有三个级别的选择工作,并且将用户选择发布到了应用程序的公共排行榜中。 进入周末时,我只剩下两个任务:编写评分算法并实现推送通知。 得分算法比我想象的要复杂一些。 这项运动会为期四天,包括13到15个项目。 我的Firebase服务器占据了三个排行榜:男性,女性和团队。 在每个事件结束时,我将进入Firebase并更新排行榜,此时,用户提交的排行榜还将根据每个事件后的人员选择的准确性进行更新。 我知道您在想什么-“真的吗? 手动更新?”我并不为此感到自豪,但我花了数小时试图编写一个脚本,该脚本会刮除排行榜更新的网页,但官方游戏网站的排行榜隐藏在javascript文件的面纱下,而所有第三个派对排行榜网站无法足够快速地进行更新。 快速旁注:锐步(Crossfit Games的冠名赞助商)发布了一个用于实时排行榜和得分更新等的应用程序,但是它在打开时会崩溃,因此我获得了一次绝佳的下载机会,因为我的排行榜更新速度比竞赛。 回到评分算法。 […]

Swift的反应式编程第1部分

如果您是iOS开发人员,那么您应该已经听说过RxSwift。 这是Reactive编程的快速版本。 RxSwift功能强大且有效,它将为您完成代码中的所有工作,并使您的开发人员生活变得轻松。 不相信吗? 比起您,我可以检查一下此介绍性的Reactive Programming,与我me —> 新手的Reactive编程 。 RxSwift漫游以下条款: –观察员与观察员 – 学科 –运营商 –调度程序 让我们开始一个个地探索所有这些东西。 可观察者和观察者: “事件A发出一些数据,订阅事件A的其他事件(例如事件B和事件C)将获得该发出的数据。 发出数据的事件(在这种情况下为Event-A)被称为“ 可观察的 ”或“ 可观察的序列 ”,并且接收到发出的数据的所有事件(在这种情况下为Event-B和Event-C)被称为“ 观察者 ”。 这是理解Observable的最简单定义。 可观察的数据可以是连续的,也可以在多个实例中发出。 观察者可以依次接收所有这些实例。 让我们检查下图: 这是上图快速显示编码的方式: let observableA = Observable.of(1,2,3,4,5,6)//创建可观察的 让observerB = myFirstObservable.asObservable() //订阅Observable readerB.subscribe {事件在 打印(事件) } 输出: 下一个(1) 下一个(2) 下一个(3) 下一个(4) 下一个(5) 下一个(6) 已完成 在这里,观察者B不断获取来自A的数据。相同的基础也将适用于其他观察者(C和D)。 您可能会对上面的输出中的“下一个”和“已完成”这两个术语感到好奇。 让我们检查一下。 可观察的生命周期: 可观测值包括三个主要事件: […]

DPImageView-Letters —创建带有缩写的ImageView

一个简单易用的UIImageView扩展,可生成带有用户背景色和双边框的首字母作为用户图像的占位符。 完全支持SWIFT 4和SWIFT 3。 TL; DR –现在,移动应用程序世界中任何图像视图的默认默认图片都是由带字符串首字母的imageview组成的。 您可以为其命名为Google或Facebook。 例如:如果我叫John Doe,那么结果将是其中包含JD作为字符串的imageview PS:您可以在此处查看其完整的GIST文件。 我将其命名为DPImageView + LettersExtension.swift 手动安装 将DPImageView-letters.swift文件从DPImageView-Letters-Header文件夹DPImageView-Letters-Header到您的项目中。 而已! 请享用! 用法 由于DPImageView-letters.swift是作为ImageView扩展创建的,因此您无需分别在每个类中导入它。 完成后,只需将其添加到您的项目中即可。 对项目内的任何ImageView调用此方法。 此方法将查找提供的文本的缩写,它将选择一种随机颜色作为背景色,它将为您提供一种使图像视图是否为圆形的方法,并且还可以为具有文本属性的imageview提供双边框变化 func setImage(string: String?, color: UIColor? = nil, circular: Bool = false, stroke: Bool = false, textAttributes: [NSAttributedStringKey: Any]? = nil) string是用于生成缩写的字符串。 如果可用,这应该是用户的全名。 color是一个可选参数,用于设置图像的背景色。 传入nil会自动为您生成一种颜色。 circular是一个布尔参数,如果启用,它将自动将图像裁剪为一个圆。 stroke是一个布尔参数,如果启用,它将自动在圆上绘制边框。 (它还为您提供双边框) textAttributes是文本的预定义字符属性的可选字典。 您可以在NSAttributedString中找到可用键的列表 如果要为给定名称保留相同的颜色,则可以使用UIColor扩展中的以下方法: static func […]

iOS自动版式4

4.kısımdayız! Bukısımdakod ile自动布局nasılyapılıronuinceleyeceğiz。 Eğergözatmadıysanızbundanönceki3yazıyagözatmanızıtavsiye ederim。 iOS自动版面3 Merhabalar Auto Layout的版本3和版本。 Eğeröncekiikibölümedahaöncehiçdenk gelmediyseniz bu… medium.com iOS自动版面2 iPhone 10(NamıdiğerEKS)重装了。 medium.com iOS自动版式1 Tümbu cihazlarda tekilgörünümüyaratmak bu kadar zor mu吗? medium.com 自动版式kullanırkenbirşeyleryaparken hepdiğeralternatiflerden bahsettik。 yinebugüncode ile Auto Layout yaparken 3yöntemdenbahsedeceğim。 布局锚 布局锚bu serinin2。yazısında伪代码olarak yervermiştim。 Burada oyazıdaki伪密码子tam code哈利尼göreceğiz Yukarıdakigrafikte bir view in olabilecektümanchorlara yer verdim。 Soldansağaveyasağdansolayazılıpokunan dilleriçin领先ve尾随anchorların左ve右anchorlarlardoğruve tersorantılıolarakdeğiştiğindenyukarıdakişemadayine durumagöreilgili deyererrere。 Tümanchorlarıgördüktensonraöncekiyazılardanaşinaolduğumuz约束denklemini伪kod […]

降低

过滤,缩小和映射: 轻按一下即可转换收藏。 这些功能上的朋友, 您将清除的代码, 输入不可变,没有陷阱。 映射和过滤器引起了很多关注,但是我说减少是重要的一环。 或者,如果您对效率感兴趣,该怎么做:您可以使用reduce来构建地图和过滤器。 如果您只想学习一种,请选择减少。 功能朋友 Map具有对序列中的每个项目执行某些操作并收集结果的有用行为。 let words = [“hello”, “there”] let shoutyWords = words.map { $0.uppercased() } // [“HELLO”, “THERE”] map的输入是大小为n的序列,输出的大小也为n 。 接下来,使用过滤器可以确定序列中要保留(和丢弃)的项目。 let numbers = 0…10 let evenNumbers = numbers.filter { $0 % 2 == 0 } // [0, 2, 4, 6, 8, 10] 输出大小将介于0到n之间,具体取决于要过滤的事物数量。 减少什么? 减少减少 像其他两个操作一样, reduce接受一个序列作为输入,但是它的输出更为通用:它可以是您想要的任何东西! […]