Tag: xcode

iOS推送通知背景下载神秘化

在实施推送通知时,我发现许多有关后台下载如何工作的不完整和不准确的信息。 我必须通过实验弄清楚其中的一些内容,以防万一它可以帮助其他人,这就是我所学到的。 (请注意,我将不介绍设置Apple Push Notifications的详细信息-这是一个完全不同的主题)。 期望的行为 至少对于我的应用程序而言,期望的行为是到达推送通知以触发后台下载,以便在用户下次打开该应用程序时(通过点击通知或正常打开该应用程序),该数据已经在那里。 此外,如果用户点击通知本身,则该应用应打开并显示该通知引用的特定视图/数据。 为了更具体一点,在紧急电子邮件和任务管理应用程序中,有关新电子邮件的通知应触发该应用程序从服务器下载该消息的内容,然后点击通知应打开该应用程序并显示该特定线程。 一个明显的问题是为什么您不能仅随通知一起直接发送所需的内容。 问题在于,Apple将通知有效载荷限制为2 KB,不足以包含大多数电子邮件的内容和元数据。 配置项目以进行通知背景下载 首先,您需要为您的应用设置适当的功能。 我假设您已经在目标设置的“功能”部分中启用了“推送通知”。 对于后台获取,您还需要在“后台模式”下启用“后台获取”和“远程通知”。 所有重要内容可用标志 其次,不要忘记在服务器发出的实际通知中将content-available设置为1,以触发后台下载。 如果您未能在通知中包含此标志,则通知到达时,您的应用将不会收到任何协议方法调用。 了解相关的App Delegate协议方法 乍一看,这似乎很简单。 UIApplicationDelegateProtocol提供了application:didReceiveRemoteNotification:fetchCompletionHandler:方法,该方法在通知到达电话时被调用。 并发症有两个方面: 当用户点击通知以启动应用程序时,也会使用完全相同的参数调用完全相同的didReceiveRemoteNotification方法。 如果通知到达时(或用户点击通知时)应用尚未运行,则通知信息将作为启动选项传递给didFinishLaunchingWithOptions,然后调用didReceiveRemoteNotification *。 同样,没有区分通知到达与用户点击通知。 因此,您需要处理四种情况: 通知到达,应用程序在后台运行。 通知到达,应用未在后台运行。 用户点击通知,应用程序在后台运行。 用户点击通知,应用未在后台运行。 案例1和3仅在案例2和4在didFinishLaunchingWithOptions的启动选项中提供通知详细信息时才调用didReceiveRemoteNotification,然后调用didReceiveRemoteNotification。 更为复杂的是,如果用户通过将其从内存中刷出而手动杀死了您的应用程序,则不会发生情况2。 也就是说,您的应用程序永远不会在后台启动以获取数据,直到用户选择再次启动它。 从用户点击通知中区分通知到达 除了一个例外,您可以通过检查应用程序状态来区分通知到达和用户在didReceiveRemoteNotification(或didFinishLaunchingWithOptions)中点击通知的情况。 如果应用程序在后台运行(UIApplicationStateBackground),则应执行后台下载。 相反,如果应用程序是“非活动的”(UIApplicationStateInactive),则表示它是响应于用户点击通知而从后台移动到活动的。 如果该应用程序已经处于活动状态(UIApplicationStateActive),则通常不需要执行任何操作。 但是,有一个重要的例子。 如果应用程序已暂停(在快速应用程序切换模式下,双击主页按钮后),并且通知到达,则应用程序的状态将为UIApplicationStateInactive而不是UIApplicationStateBackground。 但是,这并不意味着用户点击了通知。 因此,您需要其他逻辑来检测这种情况。 您可以将applicationWillEnterForeground用作其他信息。 当应用程序从后台转换为非活动状态时,始终会调用该方法,因此您可以依靠它在用户点击通知且应用程序实际上正在启动时(而不是通知到达时)被调用,而用户尚未交互。 您可以保留一个标志来跟踪该应用程序是否真正启动。 这是AppDelegate中的基本代码: -(void)applicationWillResignActive:(UIApplication *)application { self.appIsStarting =否; } […]

流行的Swift iOS图表库

大多数iOS开发人员正在学习中,或者现在正在Swift中进行全面开发。 我想快速汇总一下令人难以置信的code.com上三个评分最高的Swift iOS图表库。 这些是根据受欢迎程度,各种图表和功能选择的。 图表 流行的且恰当命名的Charts是一个很好的起点。 使用iOS,tvOS和OSX的Swift编写。 但是,值得注意的是该演示项目位于目标C中。 该库为我们提供了8种不同的图表类型: 线,条,组合,饼图,散点图,烛台,气泡和雷达 还有很多选择,例如 在两个轴上缩放(触摸手势,单独轴或捏缩放)。 使用触摸手势和组合图(线,条,散点图,烛台,气泡)进行拖动/平移。 可自定义的轴(x轴和y轴)和突出显示值(具有可自定义的弹出视图)。 将图表保存到相机胶卷并导出到PNG / JPEG。 图例是自动生成的,但也可以自定义。 2.汇票 这是适用于iOS的高度可定制的图表库,包括: 条形(普通,堆叠,分组,水平,垂直) 散点图,直线(直线/三次/自定义路径生成器) 面积,气泡,多轴。 蜡烛。 一切都是可自定义的,例如颜色,视图,单位,标签,动画,交互,轴等。 使用叠加层,信息视图等,可以轻松创建任意标记。 它使用模块化架构,应该可以轻松创建新的图表类型或添加效果。 3. PNChart-Swift-这是原始PNChart目标C库的快速版本。 它具有一些不错的动画并支持: 酒吧 线 雷达 馅饼 散点图。 如果您对此列表有任何补充,请联系我们,让我们知道。

使用Vapor Server Side Swift框架存根XCUITests

最初在XCBlog上发布在这里 毫无疑问,Swift是用于为iOS,macOS,watchOS和tvOS等Apple平台开发本机应用程序的出色语言。 但是,作为一种新语言,Swift缺少许多测试功能,就像我们在其他编程语言(如Ruby)中看到的那样。 在Swift中使用协议模拟类非常困难,并且存根网络请求的选项非常有限。 模拟是脆弱而艰苦的,到Swift时模拟变得更加困难。 Swift中没有可用的成熟模拟库来生成类似Java,Ruby,Python或其他语言的模拟。 开发人员必须手动编写所有模拟,并将测试代码与生产代码紧密耦合。 这里有一篇很棒的关于iOS网络测试的文章,以了解有关如何使用协议进行模拟的更多信息。 存根是测试代码的另一种方式,而不必依赖后端或网络。 使用存根,我们仍然可以实现网络测试的目标,并且不必将测试代码与生产代码紧密耦合。 我们将看到可用于存根的库的详细信息。 一些最受欢迎的库是用于XCTest(unit)测试的OHHTTPStubs,Mockingjay,Hippolyte。 用户界面测试贯穿网络层,涵盖了网络测试的所有方面。 苹果有XCUITest框架来涵盖Xcode UI测试。 我们可以使用一些库来为UITest存根网络。 一些流行的库包括Swifter,SBTUITestTunel和XCUITest(UITest)的Embassy。 但是,市场上出现了新的服务器端Swift框架,例如Vapor,Kitura,Perfect,它们也可以用于暂存网络请求。 在这篇文章中,我们将看到如何使用Vapor服务器端swift框架对网络请求进行存根。 Apple在WWDC 2015上宣布了Xcode的UI测试支持。UI测试被设计为完全黑盒,无需访问主应用程序代码和数据。 XCUITest使用两个独立的进程Test Runner和Target应用程序,测试运行器启动了目标应用程序,并使用UIKit内置的可访问性功能与在单独进程中运行的应用程序进行交互。 在嘲笑或测试UITest时,我们几乎没有选择 模拟和通过发射参数/环境 这意味着您不能直接模拟API。 与代理应用程序通信的唯一方法是传递启动参数或启动环境。 我们可以传递模拟API并创建启动环境变量,然后将其传递给XCUITests,但这需要大量的工作。 代码用if-else语句括起来,以确定听起来不太好的构建配置。 Web服务器存根后端并返回响应 剩下的其他选择是对网络呼叫进行存根并从服务器获取所需的数据。 为此,我们需要模拟后端并指向我们的应用程序以使用这些端点。 问题是我们是否仍可以使用上面提到的存根服务进行单元测试。 我们仍然可以使用这些库来处理网络请求,但是有时它需要更改主应用程序的逻辑,并且需要重构某些东西以增加额外的工作。 我们需要在生产代码中添加很多测试代码。 在我先前关于XCUITest的网络存根选项的文章中,我们介绍了所有选项,例如Swifter,SBTUITestTunel和Embassy for XCUITest。 现在,让我们详细介绍一下Vapor。 服务器端Swift框架尚未投入生产,但我们可以将其用于存根XCUITest的目的。 我还没有在互联网上读过任何人做的书,但是它工作得很好。 市场上几乎没有可用的Server Side Swift框架,例如Perfect,Kitura,Zewo和Vapor,但在此演示中,我们将使用Vapor。 选择蒸气的原因是它很容易学习,并且蒸气周围的社区正在迅速发展。 它完全由Swift编写,并带有易于上手的Vapor工具箱。 为了演示此功能,我创建了一个演示应用程序,当我们在文本字段中输入Github用户名时,它将显示Github用户信息。 您可以从Github Vapor-XCTest克隆该应用程序,该应用程序具有带有和不带有存根的XCUITests。 您需要安装Xcode 9+和OpenSSL,然后我们才能签出演示应用程序。 $ git clone https://github.com/Shashikant86/Vapor-XCTest […]

AppCode和单元测试

由于不稳定,XCode的质量每天都在下降。 这些天,我正在尝试AppCode,感觉好多了。 但是对于一直使用XCode的人来说,几乎不可能迁移到AppCode,因为它看起来或感觉上都不像XCode。 在我的职业生涯中,我曾从事过各种IDE的工作,从Visual Studio,PhpStorm,PyCharm,Android Studio,Eclipse,最后是用于iOS开发的XCode。 在XCode中,即使重新启动计算机后,XCode中的小菱形测试按钮也会消失并且永远不会显示,更不用说重新启动XCode了。 有没有想过为什么? 查看我的这篇博客文章,以找回它们。 这就是为什么我想尝试用于iOS开发的新IDE的原因之一,而我在这里使用AppCode。 与XCode不同,AppCode并未配置其他目标。 我们将必须手动配置它们。 请按照以下步骤操作,您将一路顺风。 从“选择运行/调试配置”菜单中单击“编辑配置”。 在打开的窗口中,单击左上角的“ +”,将弹出上面显示的菜单。 选择XCTest / Kiwi选项。 在“名称”字段中为测试目标命名。 如果要测试类或方法,只需为“测试种类”选择“类/方法”。在“类”字段中,可以将其保留为空白以测试测试目标中的所有类,也可以测试特定的类。 键入测试类的名称后,“方法”下拉菜单将显示该特定类中的所有测试,您甚至可以选择测试一个类的单个方法。 这提供了非常好的灵活性。 将“目标”设置为项目中的测试目标。 单击“应用”。现在,您将在“选择运行/调试配置”下拉菜单中看到测试目标的配置。 选择测试目标和设备,然后单击“运行”按钮。 瞧! 您的测试将开始运行。 撰写本文时使用的AppCode版本为2016.1.2。

AVAudioSession简介

这周,我将谈论一个小得多的话题,但这个话题与我的内心深处息息相关。 我从音频界开始从事iOS开发,我总是喜欢谈论Swift中的音频。 今天,我在写有关AVAudioSession的文章。 花一点时间考虑一下我们如何在应用程序中使用音频。 有时,我们会出现一些小错误和bloop来提醒用户某些事情。 其他时候,我们会提供游戏的背景音乐或视频中的声音。 有时,可以通过手机侧面的静音开关关闭声音。 一切都很好,但是如果我们有一个时钟应用程序,并且需要警报来覆盖该开关怎么办? 如果我们希望我们的应用在手机屏幕锁定时继续播放音乐怎么办? 当我们的应用程序播放声音而另一个应用程序播放音乐时会发生什么? 应用程序通过使用音频会话来处理此问题。 关于iOS应用中的音频的第一件事是,您的应用不会直接接触设备的任何音频硬件。 该应用程序通过中介与操作系统进行通信。 该中介是音频会话,特别是AVAudioSession。 看! Apple文档中的方便图形! 启动应用程序时,在幕后将为它提供AVAudioSession的单例实例。 我们的应用程序可以使用AVAudioSession的共享实例来配置应用程序中音频的行为(首先必须导入AVFoundation)。 要调整AVAudioSession的总体行为,我们可以将其设置为以下几类之一。 AVAudioSession具有一个简单的方法: setCategory(_:mode:options 🙂 。 请注意,您可以设置的类别由全局字符串常量表示,例如“ AVAudioSessionCategoryAmbient” 那么,这些类别中的每一个都有什么作用? 好吧,我不会遍历其中的每一个,因此,这里有一个方便的图表以获取更多详细信息。 AVAudioSessionCategoryAmbient是默认类别。 设置为此时,来自应用程序的音频将通过静音开关关闭,不会中断来自其他应用程序的音频,并且不会接受任何音频输入。 如果我们将类别设置为AVAudioSessionCategoryPlayAndRecord,则每个类别的情况都将相反。 重要说明:如果您打算在应用程序处于后台运行时播放音频,则必须更改info.plist文件中的某些设置。 幸运的是,Xcode有一个简单的方法可以做到这一点。 只需进入项目功能,打开背景模式,然后选择“音频,Airplay和画中画”即可。 在每个AVAudioSession类别中,可以设置许多模式,这将为您的会话添加更多功能。 同样,这些模式中的每一个都是由常量表示的字符串。 我想知道这些值是否是从较旧的Objective-C代码中遗留下来的,因为通常在Swift中,这看起来像枚举通常表示的那种。 无论如何, 这是每个列表 。 这些模式是针对特定用例进行优化的较小的性能调整。 例如,在具有多个麦克风的设备上,AVAudioSessionModeVideoRecording将打开最靠近该设备摄像机的麦克风。 仅当您设置了较大的类别AVAudioSessionCategoryRecord和AVAudioSessionCategoryPlayAndRecord时,它才起作用。 要考虑的另一重要事项是AVAudioSession的激活和停用,以及在激活或停用失败的情况下的错误处理。 首先,这是来自Apple文档的绝对荒谬的图像。 我发誓我没有化妆: 这是他们的…有关AVAudioSession激活工作原理的解释。 在适当的时间激活和停用音频会话非常重要。 如果您在激活音频会话后将其激活,则您的应用将崩溃。 这是直接从Apple文档中获得的所有内容 : let session = AVAudioSession.sharedInstance() 做{ […]

为iPhone X调整Apps UI时如何解决最常见的界面问题

在不到1个月的时间内,iPhone X就会投放市场。 全球的苹果迷迫不及待地想要购买这款外观精美的智能手机。 作为开发人员,调整您的应用程序以支持iPhone X边缘到边缘屏幕是一项不容忽视的任务。 在本文中,我将向您展示在iPhone X上运行现有应用程序时可能会遇到的一些常见UI问题,以及如何仅使用界面生成器进行一些简单的调整即可解决该问题。 请注意,我们将要讨论的问题通常在尝试在Xcode 9上运行Xcode 8或更低版本的项目时发生。但是,在使用Xcode 9创建新应用程序时,每种解决方案背后的概念仍然非常有用。让我们开始吧! 上图显示了当我们尝试在新的iPhone X上运行我们的应用程序时一个非常常见的UI问题。现在,让我们关注Label-A 。 问题的原因是因为我们假设状态栏的高度并在Label-A.Top和它的Superview.Top之间设置了垂直空间约束。 由于iPhone X的状态栏高度与所有以前的iPhone不同,因此这会导致Label-A错位到状态栏下方。 要解决此问题,我们将需要使用Xcode 9界面构建器中引入的“ 安全区域布局指南 ”。 ( 您可以 参考 Apple的 本 指南 以了解有关安全区域的更多信息 )。 首先,启用“安全区域布局指南”。 接下来,我们需要通过在Label-A.Top和Safe Area.Top之间建立关系来更新Label-A的top约束。 而已! 现在,当您尝试在iPhone X模拟器上运行该应用程序时,您将能够看到Label-A神奇地将其自身定位在正确的位置。 您基本上可以应用相同的概念来固定Label-B的位置。 只需通过在Label-B.Bottom和Safe Area.Bottom之间建立关系来更新Label-B的底部约束。 这是更改后的最终产品,这要归功于“安全区域布局指南”,您可以在iPhone 8和iPhone X屏幕尺寸上正确看到Label-A和Label-B布局。 💪 通过遵循Apple提供的指南,背景图像和UITableView(或UIScrollView)都应始终延伸到边缘并填满整个iPhone X屏幕。 上面的UI问题的原因与我们在“ 问题1 ”中讨论的原因完全相反。 以背景图片为例,屏幕顶部的间隙是由我们在ImageView.Top和Top Layout Guide.Bottom之间设置的约束导致的。 为了使图像视图占据整个屏幕,我们需要在图像视图与其超级视图之间具有顶部和底部约束。 因此,我们需要做的是将Top Layout Guide.Bottom更改为Superview.Top并将Bottom Layout […]

设置一个Xcode项目以开发可共享通用代码的Cocoa和Cocoa Touch框架,并为MacOS和iOS应用程序提供可重用和可重新分发的UI和非UI组件

缺少这样的教程,或者至少当我第一次尝试执行标题(尽可能长,但尽可能短)时,自己还没有找到。 我来到了来自C#编程的Apple开发生态系统,只是试图通过新的(很有希望的)macOS和iOS目标扩展我公司已经为Windows和Web开发提供的产品集(主要是组件库)。 由于我必须通过尝试和重试来学习所有内容,而且这并不容易(至少不应该像恕我直言,这本来应该如此简单),所以我认为写下已建立的步骤并没有什么害处(随后一些屏幕截图),也许他们也可以帮助其他人-谁知道? – 在将来。 因此,让我们开始吧。 一个项目,多个目标,没有显式工作区 我了解到的第一件事是(与.NET世界中Visual Studio解决方案通常将更多项目分组的情况不同),我不需要Xcode工作区来对多个项目进行分组。 仅仅是因为我不需要多个项目。 因为单个Xcode项目可以定义多个目标,所以每个目标都有其自己的类型和目标,并且每个目标都具有针对特定平台(例如macOS或iOS)构建的二进制文件。 (但是,顺便说一下,无论何时创建项目,无论如何都会为其创建内部工作区。) 在我的研究期间,我也没有发现对通用的跨平台层的真正技术需求(尽管我曾经习惯于在.NET中开发共享的跨平台类库。)仅仅是因为Xcode中的每个源代码文件项目可以是其一个或多个目标的一部分,而无需任何源代码重复,并且目标可以根据需要完全自定义。 因此,让我们在Xcode中创建我们的第一个项目。 我们可能会尝试从一个更具体的项目类型开始,但是我发现如果首先选择一个Empty模板(从“跨平台”选项卡下;为什么从那里选择)最简单,那是因为我们肯定会为多个平台)。 因为目标(和生成的产品)必须具有唯一的名称,所以我不得不将其中一个作为主要(我选择了macOS),将另一个作为iOS(辅助)。 对于后者的名字,我刚刚附加了“ Touch”来区分它(这个想法来自您可能已经猜到的苹果公司Cocoa和Cocoa Touch框架的名字。) 分组源代码文件 下一个挑战是找到一种在项目中考虑或不考虑其指定目标的好方法,将源代码文件分组。 我最终选择使用简单分组,并为每组源代码文件生成一个文件夹。 (Xcode确实支持不带文件夹的项目内分组,某种程度上类似于Visual Studio解决方案文件夹,但至少在我开始使用的版本9中,此功能存在一个丑陋的错误-拖动非文件夹分组的项目有时会崩溃。 ) 最终,考虑到它包含的源代码的功能区域,以及一个组包含的代码对于我的项目目标(macOS和iOS)是公共的还是特定于一个的,我决定进行多级分组。 请注意,默认情况下,为每个目标Xcode创建了一个组(和一个文件夹),我还希望将该分隔保留为我的主层次结构分组。 但是,这再次要求一个目标(我选择了macOS)成为主文件夹,并同时包含特定的和通用的源代码文件,而另一个目标(iOS目标)获得了仅保留特定源代码文件的辅助文件夹。 如果您想将其复制粘贴到您的Xcode中,这是实际的源代码: 不过,我在使用示例应用程序时发现的一个重要方面是,我们不应该尝试通过将它们移动到项目结构下的公共文件夹(在那里成为子文件夹)来对应用程序进行分组,因为它似乎有些Xcode应用程序设置不要在此过程中进行更新,并且会在构建时生成特定的警告。 但是,最终我能做的是解决这个问题,即创建一个不带名为“ Samples”的文件夹的组,然后将所有示例应用程序文件夹拖到该文件夹​​中,并将它们全部放在项目结构中的单个可折叠树节点下。 (重要的是文件路径保持不变。) 部署产品 对于每个目标,Xcode都会生成一个框架文件,其中包含为该目标构建的二进制文件和一些元数据,消费者可以使用这些元数据来访问您的组件。 您可以在项目结构中为您生成的Products文件夹中看到框架文件,并且可以通过Finder的上下文菜单在Finder中打开每个文件的位置。 然后,您可以从Finder复制框架文件并将其托管在任意位置,例如可以从Web服务器下载的文件,也可以通过您管理的任何分发渠道发布该文件。 发布配置 您可能已经看到输出框架是使用Debug配置构建的,并且您可能希望在实际部署它们之前切换到Release。 要改为选择发布配置,只需从Xcode的顶部菜单中单击目标组合框,然后单击“编辑方案”。 然后,对于“运行”选择,将“构建配置”从“调试”更改为“发行”,关闭对话框,然后重新构建目标。 体系结构:iOS模拟器不是ARM! 但是你不流行。 您最终会注意到,即使您使用Release配置构建了iOS框架(以Touch后缀命名),也无法在所有架构上正常运行。 例如,如果您使用真实设备(或具有ARM体系结构的通用设备)构建框架,则输出框架将不适用于以模拟器为目标(使用x86体系结构)的iOS应用。 反之亦然。 因此,您还需要定义一个聚合目标,以便能够运行脚本以将为不同体系结构构建的框架“合并”为一个聚合的“胖”对象。 为此,请在新目标对话框的“跨平台”选项卡中创建一个类型为Aggregate的新目标,为其命名,如“ FramisTouch-aggregate”,并为其添加一个新的运行脚本阶段(使用“ +”按钮目标的“构建阶段”部分),并定义一些命令来执行所需的操作: 然后,可以通过构建聚合目标(很重要:之后)轻松地执行上述命令:通过从目标中选择通用iOS设备和模拟器,您已经在Xcode中构建了设备和模拟器框架(即针对两种类型的体系结构)组合框,然后重复构建输出。 您当然想知道这些命令实际上会做什么: 创建一个新目录(例如“ Release-iphoneaggregated”)作为目标(在项目的构建目录中); 将基于设备的框架的结构复制到新目录中; […]

应用内购买-App Store中的Configurando Compras nos Apps

在应用程序商店购买应用程序内应用程序的渠道有所不同,应用程序商店中的应用程序发行有所不同,应用程序商店中的应用商店之间的关联性也有所提高。 如果您想解锁应用程序中的功能(例如:订阅,游戏内货币,游戏级别,访问高级内容或解锁完整版),则必须使用应用程序内购买。 应用程序可以使用应用程序内购买货币来使客户能够“提示”应用程序中的数字内容提供商。 应用及其元数据可能不包含将客户引导至应用内购买以外的购买机制的按钮,外部链接或其他号召性用语。 框架StoreKit连接到一个应用程序,或者从应用程序商店或应用程序中获取信息。 Aceitando o Regulamento Apple开发者计划许可证的法定附加条件和必要的收费应用程序协议的使用目的是使组织机构可以重复使用或重复生产应用程序。 达因斯普雷斯州的紧急收货人,达姆斯市的本可莫斯公司。 在应用内购买了10.000个付费应用内购买商品,在sua conta上购买了dodo操作系统应用。 在不同的Mesmo 应用程序内购买应用程序 (iOS e tvOS)可以在其他应用程序中使用 Mesmo应用程序。 应用内购买产品 : 消费品(消费品):一般消费品,普通消费品,高级商品的渐进式购买权。 由于没有任何复制品,所以没有任何复制,发行和发行。 Nauoconsumíveis(Non-consumables):使用us Pos Compem递补的nauoconsumíveisem um aplicativo。 消费者可通过以下方式购买自己的产品:摄影,摄影和摄影。 苹果荚果与花生的关联不包含任何消费方面的内容。 Assinaturasauto-renováveis(可自动更新的订阅):可以使用我们的服务或服务,也可以使用新的服务。 取消销售订单后,取消订单。 不可更新的订阅:(续订):使用限时提供的服务,或者继续传输的内容都可以使用。 Esse tipo de assinaturanãoérenovado autoamente,portanto,osusuáriosprecisam renovar cada vez。 Cada应用内购买功能和应用商店关联功能,以及功能强大的菜单,其中包括电子应用内购买功能。 苹果的应用程序需要新的保护和保护。 Ativando应用内购买无需Xcode 在应用程序内进行配置时,无需进行iTunes管理员即可轻松配置iTunes的功能。 在App Store上进行配置,然后在沙箱中进行环境配置。 推荐人 App Store审查指南:业务 在应用程序内购买 StoreKit文档 应用内购买文档 配置应用内购买的工作流程

使用TestScheduler测试反应式代码

TL; DR 异步反应性函数,例如Observable.interval() , Observable.timer()或您自己的异步反应性函数,可以通过沿时间轴移动被测对象来使用RxTest.TestScheduler进行测试。 真正忙碌的人可能会立即深入那里的代码: vadimue / RxLocation RxLocation –反应性使用CoreLocation github.com 简单样本 我们都写测试,不是吗? 😏有时我们甚至使用TDD。 通常,我们将Observables用于多个异步操作。 但是用单元测试来测试它们可能很棘手。 如果我们不编写DispatchQueue.main.asyncAfter()或wait(for: [expectation], timeout: 60)异步测试将失败。 否则,我们可能将Rx用于同步操作,这就是为什么我们不会在执行等待时遇到问题。 例如,让我们看一个测试,该测试涵盖了当用户点击单元格时打开带有详细说明的页面。 该测试同步运行,这就是为什么它呈绿色的原因。 与时间有关的要求 有时需要描述测试中与时间相关的要求。 如果您需要测试发送API请求并同时显示UIActivityIndi​​cator怎么办? 还是基于某些延迟下载数据? 测试可能需要一段时间才能运行,因为它们必须等待操作完成。 显然,我们旨在加快运行测试的速度,因为我们经常运行测试并且不想浪费时间。 那么我们应该如何为这些情况编写测试? 我建议从业务需求入手。 假设您创建了一个用于监视用户位置的应用程序: 您可以使用CoreLocation框架; 实现CLLocationManagerDelegate并使之具有响应性(重用来自官方存储库CLLocationManager + Rx.swift和RxCLLocationManagerDelegateProxy.swift的扩展); 使用这些扩展创建单独的服务; 之后获取微小的LocationServiceProtocol的实现。 方法location()返回原始CLLocation对象序列。 在当前的实现中,它们每秒以最简单的配置到达。 那么,需求呢? 位置数据传输应该是周期性的,取决于运行和以下规则: 传输必须至少每分钟执行一次(静止),并且位置变化超过10 m; 传输的频率不应超过每10秒一次。 为了使代码简单(嗨,SRP!),我创建了单独的类,该类将过滤虚拟位置序列。 TrackingService符合该协议: 让我们从描述第一个要求开始: 传输必须每分钟至少执行一次。 要遵循TDD,我们应该首先编写测试。 为此创建并设置XCTestCase类: 时间旅行 现在我们可以编写我们的第一个测试。 这是最终版本。 […]

以相同的功能组合委托和块

在我正在从事的项目中,我们将代码分配拆分为多个小模块(框架),其中一个用于请求唯一标识符(在服务器端生成),该标识符将在每个API请求中使用,但在某些情况下,用户必须输入密码才能生成该唯一代码,因此该模块需要在用户界面中填充一些内容,但是如何获取呢? 因为我无法向您显示我们的代码,所以我创建了一个项目以将信用卡保存在本地钥匙串中,如果找不到卡,我们将要求用户按照以下UML序列图的说明将卡的详细信息提供给我们: NS通知 我讨厌通知,它们很难调试,并且增加了代码的复杂性。 如果我们想使用它们来解决问题,我们将至少需要3条通知,这太丑陋了! 代表 委托可以是一个解决方案,但是问题在于“进行结帐”是基于区块(异步http请求)的,因此,如果我们在钥匙串中未找到信用卡,我们将取消该请求。 委托+块(或Swift中的闭包) 这是我自带的解决方案,而不仅仅是使用委托,而是在委托函数中添加了一个完成块: func creditCardNeeded(错误:NSError,完成:@转义(_ creditCard:Dictionary )->无效); 此功能的第一部分是告知代表我们需要信用卡。 第二部分(关闭部分)将用于将信用卡详细信息从用户界面发送回框架。 是时候查看完整的代码🙂 根视图控制器ViewController 在这里,我们开始结帐过程(payAction是起点)。 请注意,我们保留了要使用的闭包的引用( self.cardCompletion = complete )。 2. CardDetaildViewController 该视图控制器将用于让用户填写卡的详细信息。 3. PaymentManager:框架类 在这里,我们使用委托功能开始请求或要求提供卡详细信息。 这里的主要问题是,当用户验证其卡详细信息时,我们将使用闭包引用返回框架并继续执行任务! 您可以在github上找到完整的代码:https://github.com/Red-Mak/RMDelegateWithCompletion