Tag: swift

使用SKProduct测试Swift代码

故事 旧的可信赖的源代码-很好,它可以正常运行很多年。 是的,只有很少的无法解释的方法,没有人记得这是什么以及拥有它们的原因是什么。 还是那是一个错误修复程序? 与其保持原样,而且完全不要触摸它。 上周,我不得不重构一个古董应用程序内购买经理—用Objective-C编写的应用程序非常尊重您的要求,60%包含单元测试。 为了减少任务的繁琐性,我为自己找到了另外一个动机–不仅重构了旧代码,而且还用Swift重新编写了代码。 现在,这项任务听起来更具吸引力。 问题 如果您对主题非常了解(Apple应用程序内购买),那么编写具有基本功能的应用程序内购买经理(控制器/帮助者/其他)很容易: –从AppStore检索产品信息(标题,描述,价格等) –在App Store上购买产品 – 恢复购买。 我跳过了有关购买的冗长的基本解释,直接解决了这个问题:以前的Objective-C实现具有良好的单元测试范围。 OSMock框架实际上可以模拟所有内容,包括必要时的系统类。 例如,以下代码创建一个SKProduct类的模拟,并为productIdentifier方法创建一个存根: 静态NSString * productIdentifier = @“ com.test.identifier”; id产品= [OCMockObject mockForClass:[SKProduct类]]; [[[product stub] andReturn:productIdentifier] productIdentifier]; 再举一个例子,下面的代码允许我测试价格处理: id产品= [OCMockObject mockForClass:[SKProduct类]]; NSDecimalNumber * price = [NSDecimalNumber decimalNumberWithString:@” 1“]; [[[产品存根]和退货:价格]价格]; NSLocale * locale = [NSLocale localeWithLocaleIdentifier:@” en_US”]; [[[产品存根]和Return:locale] priceLocale]; 新代码应在Swift中。 此代码也必须是可测试的。 如何在Swift中模拟SKProduct类? […]

通过Nil-Or-Empty-Coalescing运算符(???)为空或不存在的可选项提供有意义的默认值

要解决此问题,我必须先打开可选包装,并检查它是否为nil或为空。 在这种情况下,我提供了一些有意义的默认值,例如,让用户知道他要查找的值当前不可用。 过去不久,我偶然发现了?? 运算符(顺便称为Nil合并运算符),它使您可以为nil的可选选项提供默认值。 但这不能解决可选不是null而是空的情况。 由于我不喜欢一遍又一遍地写相同的代码,只是稍微改变一下语法以反映变量名,所以我发现必须有一个更好的方法。 幸运的是,我们可以轻松扩展Optional并实现一个不错的功能来为我们做这件事。 我们只需要在扩展中编写一次解开代码,就不必再碰它了。 如果由于某种原因必须更改它,我们可以方便地在一个地方更改它,而不必经历整个项目,这确实很痛苦。 所以这里是: 那更好。 一个简单的函数,检查该值是nil还是空,并在这种情况下使用默认值。 但是,为什么我们要限制自己使用String? 使它成为各种可选功能的通用功能不是很好吗? 我认为是的,这就是为什么我更进一步。 当然,并非每个可选项都具有isEmpty属性。 字符串和数组都有它们,但是一个空的Int会是什么样子? 多数民众赞成在一个简单的解决。 我们可以使用isEmpty属性创建一个协议。 然后,我们可以限制我们的功能以查找实现上述协议的Optional。 如您所见,对于String和Array,我们甚至不需要实现某些东西,因为这些类型已经具有isEmpty属性。 现在,让我们以默认情况下没有isEmpty属性的类型实现我们的新成就,以查看它是否确实像我们期望的那样运行(我的意思是,无论如何,谁会信任计算机?) 哇,真棒。 真的行。 但是如果你像我一样,那你就是懒惰。 甚至可能是如此懒惰,以至于即使使用自动完成功能,键入“ orWhenNilOrEmpty”也已经非常费力。 当我意识到自己多么懒惰时,我想起了? 操作员。 您是否知道在Swift中可以编写自己的运算符? 当我在上面的代码上工作时,我偶然发现了这一点,这完全让我震惊。 对我来说,这是那些绝对幸运的事故之一,使我自己怀疑是否有巧合之类的事情。 这只是为了完美。 我必须立即尝试一下,这是我想到的: 我称它为“无或空”促销员,我很喜欢它。 我希望这一小部分内容可以帮助您编写更好的代码。 对我来说,这是一次很棒的学习经历。 在改进对Optional的理解的方式上(之前我从未关心过.some(wrapped)和.none,我实际上也不了解它们),我改善了对协议扩展和约束的了解,最后但并非最不重要的一点是,了解了如何编写自定义运算符。 我的建议是,每当发现自己编写相同或非常相似的代码两次以上时,就一定要研究是否存在更好的方法。

核心数据的构建块

Core Data是Apple开发的框架。 它于2005年首次用于Mac OS。 后来它于2009年在iOS上可用。我相信,现在它是最可爱的框架。 好吧,正如我提到的,核心数据是一个框架。 它还是一个对象图管理器。 它曾经将数据持久存储在磁盘上。 对象图不过是相互连接的对象的集合。 核心数据栈 核心数据堆栈不过是三个关键对象的集合,这些对象负责处理所有外部数据存储。 托管对象模型 托管对象上下文(MOC) 持久性商店协调员 托管对象模型 托管对象模型是NSManagedObjectModel类的实例。 它用来表示核心数据应用程序的数据模型。 这是初始化Core数据堆栈时的第一步。 初始化时,这通常会先加载到内存中。 资料模型 数据模型是应用程序捆绑包中的文件,其中包含应用程序的数据架构。 正如您在图1中看到的那样,受管对象模型与数据模型相连。 持久性商店协调员 持久性存储协调器是NSPersitentStoreCoordinator类的实例。 它在核心数据堆栈中起关键作用。 它在Core数据堆栈中的Managed Object Model之后被实例化。 因此,它对托管对象模型及其结构(具有模型对象)具有清晰的了解。 它保留每个模型对象的引用。 如图1所示,持久性存储协调器与托管对象模型,MOC和持久性存储连接。 因此,可以说,持久存储协调器是连接所有边缘的桥梁。 我们的应用程序中可以有多个MOC和多个持久性存储。 但是很少有多个持久性协调员。 它将多个持久性存储作为单个聚合持久性存储呈现给MOC。 托管对象上下文 托管对象上下文(MOC)是NSManagedObjectContext类的实例。 MOC可以创建,读取,更新和删除模型对象。 是我们经常互动的实例。 如您所见,这与持久性存储协调器有关。 MOC通过持久性存储协调器获取模型对象。 如前所述,我们可以拥有多个MOC。 好吧,这是核心数据的高级主题,我将在另一个故事中对此进行讨论。 受管对象上下文就像一个便笺本。 它通过从持久性存储,持久性存储协调器以及我们要存储的数据中捕获数据来创建模型图。 现在,您可以根据需要修改这些数据。 除非您将更改保存在持久性存储中,否则持久性存储将不了解更改。 NSPersistentContainer iOS 10中引入了NSPersistentContainer。此容器具有核心数据堆栈,并提供可使用的MOC。 因此,在使用它之前,您应该了解核心数据栈。 好吧,我想是时候进入代码了。 让我们看看核心数据是如何工作的。 演示版 让我们开始一个新的单视图应用程序并检查核心数据模块。 […]

我与Map kit iOS的战斗

在继续阅读之前,请简要介绍一下我。 在过去的1年中,我是一名自学成才的敏捷开发人员,在此之前,我是使用Microsoft技术进行开发的Windows / Web开发人员。 还使用PhoneGap在几个混合移动应用程序中工作。 这很重要,因为您需要根据我的观点阅读这篇文章。 一个对Mac World完全陌生的人,直到我开始开发iPhone应用程序之前,他甚至都不拥有Mac。 我们创建的PhoneGap应用主要有两种,数据列表和包含地图的应用。 使用PhoneGap时遇到了一些麻烦,我的公司不得不做出重大决定,转向使用本机应用程序。 所以我受命接管iOS 。 首先,我们创建了一个数据列表应用程序,该应用程序以很高的成功率退出市场,然后我们将新的重要事物转移到了Map上 。 该应用需要交互式地图:已实现 应在地图上列出100多个注释图钉:已实现 应该有一个弹出列表,列出注释引脚的详细信息 应该有更详细的注释图钉信息 我环顾四周,试图找到如何使其更具吸引力和直观性。 从Uber和其他类似应用中获得灵感。 我所能实现的一切都在下面,并且也已发货。 这就是我所能实现的。 我想要的更多。 几周前,我偶然发现了MapKit WWDC 2015的新增功能。它提到了detailCalloutAccessoryView 。 这帮助我实现了想要的目标。 您可以在下面看到结果 您猜对了,它在Annotation弹出窗口中是UITableView 这已经足够好了,但是我需要额外的努力。 我想自定义弹出窗口中的顶部标题,以提供更多的交互性 我在网上搜索并找到了一个SO帖子。 由此,我在标题中找到了一种自定义字体的方法。 我使用相同的技巧在此处放置了新视图,并创建了shazzam… 嗯,不是最美观的颜色用法,而是您明白了。 如果您想了解代码,请查看我的Git Hub项目。 注意:这不是一个实际的项目,只是展示如何自定义注释视图 最后一点,当我开始iOS开发时,我可以看到我无法自定义的一组标准和控件。 但是随着您的前进,您会看到iOS Map Kit尽可能具有可编辑性。 同样,所有控件。 越过障碍可能需要一些时间,但最终您会到达那里。 我可以在Twitter和Facebook上找到。

DeveloperDay#01

“ DeveloperDay”(开发者日)纪念日(yada enazındaara ara)biryayınpaylaşmayıhedefliyorum。 Yazılımcıolarak她的günkod yazmayaçalışıyorum,elbette mutlakayazılımcılarolarak pekçokfaydalısayfakeşfediyoruz,kütüphaneleriinceliyoruz birhimkiınıkınıyıuzaınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyınáyını DeveloperDay系列; akaıkkaynak,kitap,keşfettiğimyaratıcıipuçları,kitaplar vediğerdeneyimlerimibaşlıkbaşlıkyazmayıhedefliyorum。 凯西弗勒 Mobil uygulamalarda,benim enrahatsızolduğumnoktalardan birideuygulamalarıngenelinde var olankayıt/girişyapmazorunluğunuolması(kullanıcının入职的akışı)。 Elbette kimi uygulamalariçinzorunlu birakışancak Sebastian Kreutzbergertarafındanortayaatılanyolçokhoşumagitti。 Özetle,内置的iCloud内置了iCloud或iCloud的iCloud。 斯威夫特·柯德(Swift kodörnekleriile birlikteyayınlanıyor)。 Okunmasındayarar var。 https://medium.com/@skreutzb/ios-onboarding-without-signup-screens-cb7a76d01d6e#.h7m546z1n 200+ Startup’da uzaktançalışabileceğinizidüşünerekRemotive.ioaracılığıile bir listeçıkarılmış,muazzamfırsatlarçıkabilir。 2016年,有200多家初创企业远程招聘—由Remotive.io提供 Slackbot’larıbirsüredirilgimiçekiyor。 Api.aiuygulamasıileküçükbir Slack botyaptım,其他yaptığıhava durumunusorduğumda,bunu banasöylemesi。 Bu taraftayaratıcıfikirlerim var。 https://api.ai Stackoverflow’da; 她的yazılımcınınokermasıgereken kitaplarlistelenmiş,dolu dolu bir liste。 Üzerindentek […]

在WKWebView和本机代码之间创建链接

在过去的一个月中,我一直在为对产品有一些特定要求的客户工作; 他们想要一个使用特定地图组件的应用程序,就像他们在网络应用程序中使用的组件一样。 这意味着两件事:javascript🙈并试图找出如何在本机代码和将包含地图的Web视图之间进行通信。 让我们花一些时间来概述问题。 我们在这里处理两个主要组件:用于容纳地图的WKWebView和本机用户界面。 我们希望在这些组件之间双向发送消息。 当用户与地图上的某些对象进行交互时,我们需要在本机代码中触发事件以执行操作,例如显示界面元素,或触发对新视图的选择。 我们还需要从本机代码向Webview发送消息,因此我们可以将所有繁重的工作委托给本机应用程序,以最大程度地减少javascript必须进行的计算。 对我们来说很幸运,WKWebView提供了我们需要的一切。 稍作修改,我们就可以对其进行配置,使其完全满足我们的需求! 设置Web视图是很简单的,而且有据可查,因此这里不再赘述。 您可以通过代码实例化它,也可以在Interface Builder中的视图中拖动一个并为其创建出口。 我选择了后者。 让我们使ViewController符合WKScripMessageHandler和WKNavigationDelegate: 不要忘记在viewDidLoad中将网络视图的na vigationDelegate设置为self! 好了,现在我们已经拥有了Webview设置的一部分。 稍后我们将再次讨论,但是首先,我们将深入研究一些javascript。 快速免责声明:我不是Web开发人员。 如果您是经验丰富的javascript专业人士,请避开下面的代码。 我们需要在javascript中做的就是创建一些函数来处理传入的响应,并将响应发送回Webview。 我希望您对设置index.html文件感到满意,所以我不会向您展示如何做到这一点。 现在,我们可能想做其他事情,而不仅仅是记录接收到的值,但是为了解释这个概念,这样做就可以了。 假设我们要在Web视图中保留一个人员列表,那么将从本地上下文中调用addPerson函数以将其添加到Web视图中。 可以调用sendNameToNative函数将消息发送回本机代码。 让我们添加最后一个构建块,以使一切正常工作! 我们需要在loadView函数中做一些事情,所以我们将重写它。 在这里,我们将为Web视图设置一些属性,以在调用sendNameToNative函数时侦听来自javascript的回调。 您可能需要根据设置视图的方式来摆弄这个。 您可能要做的一件事是将框架更改为等于view.frame,而另一处可能解决问题的方法是在最后一行之后添加view = webview 。 这可能会带来其他问题。 这里只剩下一件事要做,实际上是在向Webview发送消息。 这是我们难题的最后一部分; 实际将消息发送到Webview。 调用此函数使我们可以在Web视图中执行javascript。 在示例中可以看到,当我们要发送字符串时,需要在其周围添加”。 现在,我们可以在webView(_:didFinish 🙂函数中调用类似的函数来设置加载时的Webview,并在与本机用户界面交互后调用它以发送更多消息。 请记住,当您处理用户输入的属性时,您可能需要对其进行验证,以免在Web视图中执行恶意的javascript。 现在您已经确定了结构,可以开始疯狂了: 实际处理响应以触发本机代码中的某些动作,例如动画或segue。 添加更多处理程序以处理来自Web视图的不同响应,从而在两者之间创建紧密连接 恭喜你! 如果您正在阅读本文,那么您已经在WKWebView和应用程序的本机上下文之间创建了连接。 这提供了很多可能性,您可以根据需要进行扩展。 如果您为此创造了一些很棒的东西,请与我分享! 如果您喜欢这篇文章,请查看 我写 的 其他文章 ! […]

使您的UI测试再次变为绿色

加入BUX之前,我从未做过任何UI测试。 在我以前的公司中, 拥有事物总是一件好事,而且从来没有发生过当您可以执行非强制性的事情时我们能够达到目标的情况。 基本上,这通常发生在早期初创企业中的大多数工程师身上。 我真的很高兴在我们的BUX代码中看到UI测试,此外,他们设法在基本的Apple工具上构建了一些不错的抽象。 我很高兴接球并积极参与改善我们应用程序质量的过程。 我不会试图说服您编写测试。 您只需每天执行一次。 这是与“我们应该使用版本控制系统吗?”相同的问题。 答案是“是的,我们应该”。 如果您仍然需要一些启发,可以从我的一位同事撰写的文章开始。 除了要点之外,您还会发现一些很棒的历史见解。 UI测试的主要目的是快速运行最重要的方案。 我们应该能够从用户的角度跟踪是否破坏了某些内容。 当然,我们应该不时看到测试失败! 这就是测试如何帮助我们提高软件质量的方式。 但是,在某些情况下,我们可以进行红色测试,而背后的原因对我们而言似乎毫无意义,因为我们无法采取任何措施对其进行修复。 在第二部分中,我想讨论使您的测试变成红色的主要原因:网络。 烦恼网络的原因 想象一下,您刚刚为应用程序流程的新部分编写了全新的UI测试。 您击中Cmd-U时,看到Xcode的“测试成功”并提交时,微微一笑。 您觉得一切都完成了。 但是,当涉及到CI时,情况可能会发生变化。 您一定会看到红色测试的一天。 发生这种情况的原因可能很多: CI环境与开发环境不同步(例如,需要更新Xcode) 证书已过期 网络/后端失败(最常见的情况) 后端通常有多种原因完全不响应或以意外方式响应: 服务器维护 网络可达性问题(如果您使用真实设备进行测试,并且该框中的WiFi信号较弱) 与数据相关的问题。 我们不能总是知道要从后端接收什么数据 如果您的团队中有人要求您使用真实的服务器进行UI测试,请说“ 否” 。 如果他们想在不付出额外努力的情况下测试API,则应该使用一些适当的集成测试,而不是移动应用程序。 使用移动UI测试作为集成测试并不是最好的方法,因为我们引入了多个故障点,这使得测试对于移动端和后端均不稳定且无用。 即使一个应用程序可以一直访问其后端服务器(假设后端始终在运行),它仍然是一个巨大的依赖项,我们对它没有任何影响! 因此,每次在配置项上看到红色测试时,都应确保我们使用新的提交破坏了测试。 我们不会每次都检查后端/网络问题。 归根结底,每个人都可以习惯于“红色”测试,而这并不是我们想要的方式。 解决方法 我们该如何克服呢? 我们应该从不使用真正的UI测试后端开始。 我们决定从OHHTTPStubs开始,因为我们已经使用它进行了一些存根。 这件事太神奇了,它为我们节省了很多时间。 在BUX,我们决定走得更远,并包装此库以使事情更干净和可维护。 我们的目标是在决定“我是否有时间为该功能编写测试或……吗?”的情况下,轻松创建新的UI测试。 要求 我们对存根工具的主要要求是: 存根文件(很多,目前大约有300个)应该易于维护 系统应该有可能为同一端点返回不同的存根 我们应该能够以可预测和干净的方式对其进行修改以满足新的要求 单个测试流程应能够按特定顺序使用不同的存根 […]

IGListKit —将UITableView迁移到IGListCollectionView

IGListKit是Instagram发布的数据驱动框架,可帮助我们创建快速灵活的UICollectionViews。 实际上,它还提供了许多其他功能,例如动画和线性复杂度差异计算,使我们的应用看起来更凉快。 今天,我将展示如何将UITableView迁移到IGListKit。 首先,我们需要一个使用UITableView的应用程序,因此我们将使用Thiago Lioy的Marvel App。 您可以在github上查看他的代码,以及他如何以中等方式创建这个很棒的应用程序。 在安装IGListKit并开始使用它之前,让我们看一下Lioy的代码。 在CharactersViewController我们可以看到TableView以及它的委托和数据源,其中使用了Character数组。 首先,我们需要安装IGListKit。 这可以通过可可足类或迦太基来完成。 使用cocoapods,您的pod文件中将具有以下内容: pod ‘IGListKit’, :git => ‘https://github.com/Instagram/IGListKit.git’, :branch => ‘master’ 现在,我们可以从更改Character模型开始。 我们的模型应符合IGListDiffable协议。 我们可以通过扩展来做到这一点 IGListKit使用了一个有趣的适配器概念,它可以将对象分解为称为SectionControllers的各个部分。 每个SectionController负责一个可以具有多个单元格的节,但是在此示例中,我们将仅具有一个单元格。 现在,我们可以创建一个名为tableCharacterViewController.swift的新UIViewController 。 在此文件中,我们有一个IGListCollectionView,一个IGListAdapter并实现IGListAdapterDataSource。 您可以在github上检查此应用程序。 您可以在第二篇文章中检查如何使用不同的单元来改进IGListCollectionView并处理触摸事件。

使用自定义标签栏控制器

Tabbar Controller是iOS中最受欢迎的容器控制器之一。 几乎所有流行的应用程序都使用此控制器,例如Facebook,Youtube,Instagram,LinkedIn,Airbnb等。如果要在iOS中工作,则很有可能必须使用此组件。 标签栏控制器界面的每个标签都与一个自定义视图控制器关联。 当用户选择特定的选项卡时,选项卡栏控制器将显示相应视图控制器的根视图,以替换任何先前的视图。 在Apple提供的文档中,您可能会注意到Tabbar Controller的此示例图像: 在这里您可以看到,只需用手指轻按即可转到不同的屏幕。 导航非常方便。 今天,我们将尝试实现一个小的测试应用程序,该应用程序将使用Tabbar Controller,它具有五个选项卡,每个选项卡具有不同的背景颜色和标题。 另外,如您在上图中看到的那样,当选中某个选项卡时,该选项卡将变为黄色,而当未选中该选项卡时,该选项卡将变为灰色。 为了获得这种效果,我们将需要两个不同的图像用于相应的选定和未选定条件。 足够的理论可以使我们的手变得肮脏。 启动Xcode,创建一个新项目。 如果运行,您将看到一个空白的视图控制器。 这是因为ViewController类从情节提要中指向rootViewController,并且当然没有Tabbar控制器。 因此,让我们继续创建UITabbarController的子类,将其命名为MainTabbarController,并在AppDelegate的didFinishLaunching方法中将其设置为rootViewController。 这是该代码: 这是我们要构建的Tabbar控制器。 在这里,我们看到5种不同的视图控制器,例如Home,Search,Plus,Like和Profile控制器。 现在,搜索控制器处于选定状态。 创建一个名为setupViewControllers的函数,并将以下代码添加到该函数中: 现在,我们将向该应用程序添加一些奖励功能。 假设我们想将登录/注销功能与UITabbar Controller集成在一起。 处理这种情况的正确方法是什么? 让我们找到这个东西。 注销功能非常简单。 将以下代码放入ProfileController中: 看,没有选项卡栏项。 按下取消按钮,您将找到全部。 我特意带来了这个小功能,因为我希望您习惯于使用制表符栏控制器委托方法。 您可以从GitHub下载该应用程序的源代码。 链接在这里 : https://github.com/salehmasum/CustomTabbarController 希望您喜欢这篇文章。 感谢您的阅读。

使用QLPreviewController快速显示文档

从远程URL显示文件。 假设我们有一个必须在应用程序中显示的文档的远程URL。 在显示任何此类文档之前,我们必须将文件下载到app目录,然后才能显示该文件。 为什么不应该将远程URL作为QLPreviewItem传递? 您可能会认为QLPreviewItem是NSURL类型,我们可以执行类似的操作以直接显示文件。 QLPreviewItem = remoteURL 为! 网址 是!! 我们做得到。 该文档也可能会显示。 但这不是处理远程URL的正确方法。 如果我们不下载就显示大尺寸文档,则将看不到它们。 共享文档时可能会导致崩溃。 所以这就是我们要做的。 看图 我们将异步下载文件,下载后,文件应从临时 位置移至destinationURL 。 并且此destinationURL将用于在QLPreviewController中显示文件。 见图,我们在完成块中返回fileLocation 。 如果您不知道完成块。 看看链接。 同样,我们都已设置为显示来自远程URL的文件。 我们只需要按下按钮displayFileFromURL(_ sender:UIButton)。 您可以从我的Git存储库QuickLookDemo下载完成的演示项目。 摘要 伙计们,这一切都是关于我对Quick Look框架的经验。 我最近使用了此功能,因此想与大家分享。 尝试一下,让我知道我是否错过任何事情。 祝您好运,如果您喜欢或学到新东西,请推荐并分享。