Tag: swift

了解Swift的依赖注入

在进入其应用程序之前,让我们介绍一些基本概念和术语。 依赖注入是一种软件设计模式,它着重强调了服务与客户端之间的松散耦合。 服务是依赖关系, 客户端是依赖关系。 很好吗? 但是……那到底意味着什么? 倒退一步,依赖注入也称为控制反转 -听起来很复杂,但实际上意味着,自定义方法和框架之间没有抽象层,而不是直接从框架中调用函数的自定义方法。 该层通常是服务遵循的某种通用协议,这实际上是注入的关键。 还是很困惑? 不用担心,我认为是一个例子。 假设我们有一个Restaurant类和一个ItalianCuisineChef类,如下所示: 这很棒,但是您可以看到Restaurant类与ItalianCuisineChef类结合使用,如果我们决定支持多种美食,那么这将降低此代码的可重用性,例如JapaneseCuisineChef和FrenchCuisineChef。 使用我们当前的实现方式,我们将不得不为这两种菜式创建新的餐厅,从而复制我们已经拥有的许多代码。 那么,如何通过使用依赖注入来提高代码的 可重用性呢? 如前所述,依赖注入的使用取决于通用协议的使用,该通用协议将充当客户端和依赖之间的抽象层–在本例中分别为Restaurant和Chef类。 让我们从可以使用的协议开始: 我们可以将此协议用作所有Chef类之间的公共链接 。 看看新的厨师班。 如您所见,尽管两个Chef类具有不同的实现,但是它们都符合RestaurantWorkable协议,并以自己的方式实现了这些一般任务,例如prepareLunch()和prepareIngredients() 。 但是正是由于与RestaurantWorkable保持一致,才使它们可以在Restaurant类中互换。 为了实现这种多功能性,我们将修改Restaurant类的初始化程序 (构造函数),以便注入依赖项-我们要做的就是使Chef参数的类型为RestaurantWorkable。

掌握Swift:它的演变和性能

作为一个对这个不断发展的生态系统充满热情的长期移动开发人员,我一直对尝试遇到的任何新框架或语言感兴趣。 与移动平台的十年合作给了我很多机会,成为突破性进展的见证人。 对于任何Apple开发人员来说,Swift语言绝对是向前迈出的一步,并且直到Objective-C降级为“旧版代码”类别才不久。 今天,我们将探讨Swift的历史,Swift是一种年轻而有前途的语言。 雨燕简史 如今,Swift已成为Apple开发人员的标准编程语言。 自2014年发布以来,Apple开发者社区张开双臂欢迎它来替代Objective-C,这是与其他平台的主要语言相比,大多数人都认为过时的语言。 比较不同的语言和平台通常会变成偏好和品味的战斗,结果和观点因作者的技术偏好而有偏差。 但是,Objective-C的一个优点是没有人可以否认,这是一个很大的优点:性能。 实际上,在Swift首次亮相时,许多论坛上提出的第一个问题是“性能如何?”。 人们担心,更优雅的语言的价格会明显降低性能,并且大多数人不会接受这种交换。 更高版本的改进 因此,与Objective-C相比,Swift慢吗? 是的,是的,速度很慢。 正因为如此,许多早期采用者拒绝了该语言,并鼓励社区坚持使用Objective-C,因为它们的生产声明太慢而无法完成。 幸运的是,Apple通过Swift 1.2的发布迅速扭转了局面,上面提到的同一位作者就此发表了一篇新文章,只是这次的性能还算不错。 这两篇文章都值得一读。 在更高版本(版本2和3)中,Swift进行了一些重大更改。 这些更改对于使语言变得成熟和一致非常必要。 从长远来看,Swift变得更简单,更可预测且语言更加一致。 语言增长的崇高目标,但并非没有代价。 几乎每个Swift版本都具有重大更改,需要对任何应用程序源代码进行大量调整才能使其能够在新版本中进行编译。 再一次,听到了社区的抱怨,随着Swift 4的到来,Apple设定了这个新版本的主要目标, “为Swift 3代码提供源代码稳定性。” 从代码迁移的角度来看,Apple文档的一份声明指出,Swift 3和Swift 4代码之间的差异预计将比从Swift 2.2到Swift 3的跳转小得多。 那么,Swift 4呢? Swift 4将提供一种编译模式(-swift-version 3),使那些还没有准备好采用此新版本引入的重大更改的人可以更轻松地进行操作。 Swift 4发行版的总体目标是收敛并与核心目标保持一致,并达到成熟度,以在将来提供更稳定的发行版。 “随着发行版的融合,将变更纳入4的标准将变得越来越严格。” -swift.org/blog-。 为什么选择Swift over Objective-C? 可维护性:减少了样板代码,相对于Objective-C的标头和实现文件,使用了单个文件。 这样可以减少代码,从而减少所需的维护。 更好的内存管理:虽然Objective-C具有自动引用计数功能,但并非所有API(例如Core Graphics)都实现了它。 Swift为所有API提供自动内存管理。 代码更安全:这是简化指针处理的结果。 可读性:显然,Swift比Objective-C更易于阅读。 支持名称空间:集成多个项目时不再发生名称冲突。 动态库:减小了应用程序的大小,灵活性并提高了加载时间的性能 性能:对Swift的持续改进使该语言在许多标准基准测试中均紧随C ++。 […]

可视化初学者的循环输入(Swift 3)

熟悉循环对于使用任何语言进行编程都是必不可少的,而且当您刚入门时,事情可能会变得有些混乱。 在本文中,我将提供一些基本示例,这些示例应有助于您直观地了解运行时for-in循环在做什么。 这应该使您更好地了解代码的执行方式以及使用循环的时间。 基本 在第一个示例中,让我们看一个标准的for-in循环。 在此循环中, 索引从1的值开始,并且每次我们迭代for循环直到索引达到5时, 索引都会增加1。 for循环中唯一的语句是print(index) ,它在控制台的新行上打印index的值。 这样我们得到以下控制台输出。 与其将这些数字打印到控制台,不如将它们添加到阵列中。 在这里,我们从一个名为myArray的空数组开始,然后使用append(index)方法将index的值添加到myArray中 。 每次我们迭代for循环时都会调用append()方法……因此我们将索引值相加5次。 若要查看实际效果,请在for循环内添加print(myArray) 。 我们可以通过for循环的每次迭代来观察myArray的状态! 对于通过for循环的每次迭代, 索引值 被附加到myArray的末尾,然后打印到控制台。 嵌套循环 当您在一个循环中放置一个循环时,这称为嵌套循环。 在编码时,它并不总是最有效的解决方案,但在浏览或创建新集合时可能很有用。 当您运行具有嵌套循环的程序时,很难准确地分辨出每个循环在做什么以及何时执行。 希望这些示例将帮助您可视化for循环如何构建或移动数据。 看一下下面的字符串数组 。 blueEmojis包含5个(精心选择的)蓝色emoji表情, redEmojis包含3个(完全随机)红色emoji表情。 让我们使用一个for循环从我们丰富多彩的集合中制作字符串。 在这里,我们声明了一个变量,它将保存我们的表情符号字符串。 在它的下面,我们有了第一个for循环,以循环访问blueEmojis Array 。 emojiString以空白字符串开头。 使用for循环,我们可以在其中附加表情符号! 接下来让我们分解一下for循环〜 blueEmoji (否)表示blueEmojis 数组中的单个值。 blueEmoji以blueEmojis中第一项的值开头 ,并使用.append(blueEmoji)将其附加到emojiString中。 它遍历数组,直到所有值都被迭代为止。 让我们看看如果在循环中添加print()函数会是什么样子。 如您所见, blueEmojis数组中的每个表情符号都已添加到emojiString中并打印到控制台 每次我们迭代for循环时。 现在让它嵌套在redEmojis 数组的另一个for循环中, 并带有自己的append()和print() ,看看会发生什么! 如果我们查看控制台,可以看到在添加第二个blueEmoji之前,所有三个redEmojis都已添加到字符串。 这意味着在blueEmoji for循环可以完成一次迭代之前, […]

在Swift中使用字符集

它们并不是特别常见,并且您不会像在数组,字典或循环中那样频繁地在代码中遍历它们。 但是,当您确实需要它们时,它们可能会非常有用。 我在说什么 字符集! 第一次我真的需要使用一个字符集时,初始化和实现一个字符集无疑使我感到困惑,因此,我当然想进一步探讨这个主题。 什么是字符集? Apple告诉我们,字符集是一种类型的集-一种无序的唯一元素集合-包含符合Unicode的字符。 由于它们是无序的并且不包含重复项,因此字符集通常用于搜索操作,而不是用于存储和访问信息。 创建自己的字符集很容易。 下面,字符集元音被初始化为包含字母a,e,i,o和u 。 将字符集付诸实践 现在,我们可以使用此字符集在字符串中进行搜索。 假设我有两个常量字符串, fullWord和shortWord: 这些字符串是否包含元音中的任何字符? 我们如何检查? 我发现做到这一点的一种方法是使用rangeOfCharacter(from:)函数,该函数将字符集作为参数。 (由于使用该功能不能使字符集无效,因此还需要将其拆开。) 虽然这很笨拙,但肯定有一些更优雅的方法可以找到答案。 嗯 有什么我想念的吗? 字符集还有什么用呢? 字符集类型属性 字符集的一个非常有用的方面是它们的类型属性。 基本上,这些都是基于Unicode类别的预包装字符组,可供您使用! 这些类型属性的一些示例是: 您可以在Apple的API参考中找到完整的字符集列表。 让我们在下面更详细地研究其中的一些。 标点属性 如果您对字符集可能包含的内容有所了解,但又不了解每个字符的详尽列表,那么字符集类型属性将是极好的选择。 例如,想到标点符号。 如果您想删除字符串中的所有标点符号,而只剩下字母,该怎么办? 您将搜索并排除哪些标点符号? 我想取出句号 , 逗号 , 感叹号 , 问号 , 冒号 , 分号 , 连字符 , 破折号 , 撇号 , 引号 , 正斜杠 […]

使用动画和不使用故事板的iOS登录/注销的最佳实践

众所周知,移动应用程序的范围正在日益扩大。 即使这样,登录页面/模块也不是一件容易的事。 因此,完成可测试,可重用和用户友好的登录编剧非常重要。 这篇文章旨在展示iOS登录/登出时的最佳做法,而无需情节提要,而是带有动画。 TL; DR 如果您只是对项目感兴趣,而不对故事感兴趣,那么这里是github存储库: ogulcan / iOS登录示例 iOS登录示例–一个示例iOS应用程序展示了如何在没有故事板 github.com的情况下处理登录/注销 分步指南 0.简介 考虑一下登录方案。 对于大多数应用程序,登录不是应用程序的真实部分。 通常,登录是要采取的步骤。 并且在必要时需要重新应用这一步骤。 例如,如果令牌已过期或用户更改了密码等。 因此,当应用程序启动时: 1.需要知道用户是否已登录或令牌未过期或用户未被禁止等。这意味着应用程序应检查相关服务。 2.如果用户正常,则意味着已登录,首页应显示为下一页。 如果用户不满意,则意味着应再次登录,登录页面应显示为下一页。 3.设置一些假登录,如果我们使用一些动画会更好。 这些是我要采取的步骤。 让我们开始。 1.检查用户 您可能希望在UserDefaults上保存用户。 否则令牌可能永远不会过期。 即使不推荐,事实并非如此。 因此,您可能不需要检查用户是否仍在登录。尽管我仍然建议您遵循以下步骤。 通常建议使用以下方法: 在didFinishLaunchingWithOptions内部的AppDelegate.swift中,检索用户数据并确定应显示哪个视图控制器。 并如建议的那样,让我们​​创建一个名为AppStoryboard的文件来定义每个故事板文件。 还有UIViewController扩展。 我们准备以更简单的方式启动每个视图控制器。 3.登录/注销操作并进行动画处理! 现在,如果我们运行该应用程序,我们将面临登录屏幕,因为我们没有任何令牌。 让我们实现登录和注销IBAction。 首先,我们需要一个更新RootViewController的方法/扩展。 每个IBAction使用钥匙串删除或保存令牌并设置视图控制器。 最后,如果我们运行该应用程序,则每个按钮都可以正常工作。 如果仅点击登录并重新启动应用程序,我们将面对主视图控制器。 精细。 为了更好,让我们添加一些动画。 首先,我们需要更新UIApplication扩展。 这是新版本: 准备使用。

带有快速枚举的简单音乐音调值

我从事的乐器应用程序通常包含音乐理论部分。 这可能是一个简单的大尺度或更复杂的算法。 通常,我最终只使用MIDI音符编号来获取音高值。 结果最终看起来像: let cMajor = [48, 50, 52, 53, 55, 57, 59] 我决定做一些工作来制作一个可以在项目中重复使用的简单模式,以使代码更易于阅读。 代码很短,所以我将从此开始: enum Pitch: Int { case C = 0, Cs, D, Ds, E, F, Fs, G, Gs, A, As, B } 现在我可以写: let cMajor :[Pitch] = [.C,.D,.E,.F,.G,.A,.B] [Pitch]的显式类型允许我只键入.G而不是Pitch.G ,我认为它看起来更好。 概念 理想情况下,我将能够将音高作为偶然的音符名称来编写。 这些值看起来就像C♯或D♭ 。 这些值将是类型安全的,并且像原始类型一样起作用,如果我错误地输入了假间距,则会导致编译器抛出错误。 设计决策 当我经历一些选择时,我意识到我将不得不做出一些妥协。 没有Unicode意外情况: ♯和♭不在Swift支持的Unicode范围内。 有替代符号,但默认字体未包含这些替代符号,因此代码可移植性成为一个问题。 我为竖琴选择了一个简单s后缀。 […]

Swift快照测试简介

因此,我正在制作一个新的应用程序,我很乐意在进行过程中分享自己的所有经验,以便保持自己的积极性并分享一些知识,希望您可以自己使用应用。 为什么要测试UI? 很简单,您要确保每次触摸任何UI元素时,一切都保持原样,这种集成测试还可以帮助您实现像素完美的视图并通过设计使设计师满意他们甚至在您的拉取请求中也可以看到的参考图像 。 怎么样 我将尝试描述如何使用坚如磐石的facebook lib`FBSnapshotTestCase`测试所有UI组件和视图。 正如lib参考资料所述: “快照测试用例”采用已配置的UIView或CALayer并使用renderInContext:方法获取其内容的图像快照。 它将快照与存储在源代码存储库中的“参考图像”进行比较,如果两个图像不匹配,则测试失败。 为了安装库,我们将使用Cocoapods安装依赖项 将以下行添加到您的Podfile中 之后,使用终端在项目根文件夹上进行Pod安装 ,然后打开生成的工作区以配置应用程序架构,如下所示 之后,您可以进入运行方案并将此环境变量添加到项目中 FB_REFERENCE_IMAGE_DIR = $(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages IMAGE_DIFF_DIR = $(SOURCE_ROOT)/$(PROJECT_NAME)Tests/FailureDiffs 看起来像这样 完成所有这些设置之后,我们将实际构成测试部分,您需要记住,我们可以测试任何UIView或CALayer因此,要检查的任何视图在添加新的测试用例 (包括UIViewController)时都比较容易 要测试什么? 就像我说过的,您可以测试要从UIView或CALayer继承的任何内容之前, 所以在这种情况下,我将测试设计师设计的新按钮组件 在这种情况下,我们要测试每个按钮的状态,以便当我们意外更新或更改任何GenericButton代码时,如果出现错误,则测试将失败 因此,让我们开始添加一个新的单元测试用例 然后更新代码,以便我们可以开始使用FBSnapshotTestCase。 为了使用该库,我们需要导入FBSnapshotTestCase ,然后将XCTestCase更改为FBSnapshotTestCase ,更改后将如下所示: 首先,让我尝试向您解释这个概念,以便您了解其工作原理。 为了进行快照测试,我们应该首先拍摄当前视图组件,此后,库将存储参考图像,以便以后每次运行此测试套件时,可以将其与新更改进行比较。 为了拍摄第一个快照,我们应该添加一些测试用例,然后在设置方法中将recordMode变量激活为true 按下测试操作后,您将看到所有UI测试失败的原因,请不要担心这是该过程的一部分,因为您会看到一条消息,告诉您现在所有参考图像都已保存,您可以打开recordMode为false并再次运行测试 如果要验证是否创建了参考图像,则可以检查测试文件夹,如果一切正常,则应看到一些具有实际组件状态的图像,在这种情况下,所有按钮状态均作为设计标记 但是我们还没有完成,我们想检查一下它是否有效,因此每当发生任何变化时,测试目标上都会出现红灯,因此我们应该从设置中删除recordMode行,然后再次击中测试目标 从现在开始,每次更改GenericButton组件中的某些会影响设计状态的警告时,都会警告您并且测试将失败,此技术可用于视图控制器,因此根据视图的状态,您可以查看元素是否到位一切正常,您还可以与设计人员共享参考图像,以便他们检查像素是否完美。 尾注 还有其他方法可以通过使用诸如KIF或Google的EarlGrey之类的库来测试UI元素,但我认为这种快照测试更易于维护,其中一个FBSnapshotTestCase可能与许多其他框架相同。 如果您有任何疑问或疑问,可以通过Twitter与我联系,我会尽力帮助您。 这是我的第一篇英文书面文章,请原谅我的错字🤓

如何将Ad Exchange实施到iOS应用中

因此,您想在闪亮的新应用中实施广告吗? 或者,也许您正在公司中的某个项目上工作,而该项目中需要广告? 无论如何,最好的方法(IMHO)是使用Google广告服务(此帖子将处理Ad Exchange,但如果您将目标定位为Firebase / AdSense,则过程基本相同)。 尽管Ad Exchange和AdSense看起来是一样的东西(至少对于我来说,仅是从服务的技术方面来看这方面的开发人员而言),但是在这两种服务上还是有很大的不同。 Ad Exchange更像是大型企业的高级选项,它提供了更多高级功能,例如匿名性,设置首选交易的能力,比AdSense提供更多的过滤和屏蔽选项,等等。 在本文中,我们将假设您(作为读者)对iOS开发领域有所了解,并且您熟悉诸如可可豆荚之类的术语。 此外,我们还将假设您已经配置了Ad Exchange帐户,已经配置并设置了广告单元ID。 让我们从横幅广告开始(因为我认为它们是最好的广告)。 首先,我们需要安装Google Mobile Ads SDK,首选的安装方法是通过可可豆荚安装它们,也可以通过下载SDK手动进行。 之后,将其复制到您的项目中。 如果您选择使用可可豆荚 ,请添加以下行: pod’Google-Mobile-Ads-SDK’ 到您的podfile,然后通过运行“ pod install”安装SDK。 现在,您的SDK已安装并准备就绪,成为有趣的部分。 首先,我们需要确定横幅广告的尺寸。 几乎没有可供选择的选项: 我们将选择第一个选项,即320×50尺寸的广告,它完全可以满足我们的需求。 现在要做的第一件事是创建广告视图,最简单的方法是通过故事板。 因此,打开情节提要,在屏幕底部创建一个尺寸为320×50(或您选择的任意尺寸)的小视图,对其进行约束,然后在身份检查器中为其指定GADBannerView的类名。 现在是显而易见的部分,从该视图到ViewController创建IBOutlet,并将其命名为“ bannerAdView”。 最后,添加用于配置和加载广告的代码。 配置非常简单明了。 但首先,请确保将SDK导入到您的视图控制器中,如下所示: 导入 GoogleMobileAds 现在创建请求,但请确保使用测试广告单元ID,或指定一个测试设备(在我们的示例中,这是模拟器): 让req = GADRequest() req.testDevices = [kGADSimulatorID] 现在,将一些信息添加到bannerAdview中,例如adSize,根视图控制器和广告单元ID: 自我 .bannerAdView.adSize = kGADAdSizeBanner 自我 .bannerAdView.rootViewController = 自我 self […]

iOS 10远程通知

在iOS 10中,通知发生了很大变化。 远程和本地通知方法是统一的。 您可以使用通知扩展名添加图像之类的媒体。 在本文中,我将讨论如何设置通知类型和注册远程通知。 在下一部分中,我将向您展示如何处理远程通知和可操作的通知。 远程通知过程 首先,了解如何使用远程通知会很有帮助。 远程通知涉及以下步骤: 配置您的通知类型并注册远程通知 注册到APN的远程通知 将设备令牌注册到服务器(推送通知提供程序) 在提供商和APN之间进行通信 处理远程通知 步骤3和4是服务器端过程。 步骤1.配置通知类型并注册远程通知 1)配置通知类型 您需要请求授权才能接收通知。 在此阶段,您可以设置通知类型,例如警报,声音和标志。 在iOS 9及以下版本中 使用`registerUserNotificationSettings`方法 在iOS 10中 使用`requestAuthorization(options:completionHandler:)`方法。 func requestAuthorization(options:UNAuthorizationOptions = [], completeHandler:@转义(Bool,Error?)-> Void) 选项描述您要提供的通知类型。 completeHandler具有两个参数: Grant和error –如果未发生错误,则错误为nil 。 – 授予的返回true或false取决于以下情况。 这不是我期望的结果。 为什么? 授予所请求选项的授权时,此参数的值为* true *。 当一个或多个选项的授权被拒绝时,该值为* false *。 在Apple文档中,他们谈论的是请求的选项,而不是通知设置。 但是实际的测试结果与上面的列表不同。 即使用户更改了授权选项(例如在设置应用中禁用警报),它也没有返回“ false”值。 首次启动应用程序时,“授权请求”对话框仅出现一次。 因此,我建议您将`.alert`选项设置为默认选项。如果您从`registerUserNotificationSettings`或`requestAuthorization(options:completionHandler:)`中省略了该选项,则无法在设置应用程序中为您的应用程序通知找到警报选项。 2)注册远程通知 调用registerForRemoteNotifications()方法。 如果注册成功,它将自动调用` […]

您的委托方法可能不会在Swift 3中调用

Swift 3最明显的变化之一就是其命名约定。 在发布Xcode 8时,Apple还重命名了许多方法。 为了使新的Swift API与现有的Objective-C API兼容,Swift编译器将Swift 3方法转换为相应的Objective-C选择器,但有时这种转换不会发生。 最坏的情况是,您实现了委派方法,但从未调用它,并且您也不知道为什么。 在Swift 3中命名 Swift 3试图减少冗余。 在Swift 3之前的Objective-C或Swift中,我们曾经在方法的主体中包含参数名称,但现在其中许多参数已被删除。 苹果更新了其API指南,并在Cocoa和Cocoa Touch框架的Swift 3界面中重命名了许多方法,以遵循Swift 3的约定。苹果不仅更改了基本方法,还更改了协议中定义的委托方法。 例如,我们可以在Objective-C中使用一个委托方法,其选择器是“ collectionView:layout:sizeForItemAtIndexPath: ”,而在Swift 2中,它是 func collectionView(collectionView:UICollectionView,布局collectionViewLayout:UICollectionViewLayout,sizeForItemAtIndexPath indexPath:NSIndexPath)-> CGSize “ IndexPath”出现三次。 Swift 3将其视为冗余,应将其删除。 因此,在Swift 3中,它变为: func collectionView(_ collectionView:UICollectionView,布局collectionViewLayout:UICollectionViewLayout,sizeForItemAt indexPath:IndexPath)-> CGSize 如果您在类的主体中实现协议,则Swift 3的命名和Objective-C桥之间的转换将非常完美。 但是,如果您声明一个类面对某个协议,但是您在Swift扩展中实现了该协议,则Swift编译器不会进行此类转换。 Swift扩展中的委托方法 让我们来看看。 我们这里有一个UIViewController子类,它有一个UIColllectionView,它需要面对UICollectionViewDataSource和UICollectionViewDelegateFlowLayout协议。 现在看起来很完美。 如果将这些方法移到扩展中怎么办? 提出了几个错误。 它说: 方法’collectionView(_:layout:sizeForItemAt :)’提供的Objective-C方法’collectionView:layout:sizeForItemAt:’与需求的选择器不匹配(’collectionView:layout:sizeForItemAtIndexPath:’) 和 方法“ collectionView(_:cellForItemAt :)”提供的Objective-C方法“ collectionView:cellForItemAt:”与需求的选择器不匹配(“ […]