Tag: swift

Swift中的内存管理,具有强而弱的无人参考

对于iOS应用程序,学习内存管理至关重要。 您正在使用Objective C还是Swift,但是您需要熟悉内存管理将如何有所帮助。 从本文开始,我假设您对Objective C以及对OOP的Swift和清晰概念,闭包,可选和属性有一些了解。 基本上,内存管理是引用计数,在Objective C或Swift中,当您在代码中引用变量时,其保留计数会增加,反之亦然。 如果变量的保留计数达到0,则将释放该变量。 您已经知道swift使用ARC(自动引用计数)来管理应用程序的内存使用情况。 因此,您不必自己担心内存管理。 但是,您需要知识来管理代码中的内存,以避免内存泄漏。 当您创建任何新的变量实例时,ARC会分配内存来存储信息,而当不再需要该变量时,ARC将释放分配给该实例的内存。 您需要确保一旦变量被释放,就无法再次访问它,否则您的应用程序将崩溃。 初始化任何变量或对象时调用Init(),而对象的引用计数达到0时,调用deinit()取消对象或变量的分配。 下面,我编写了示例代码以更好地理解。 实际上deinit块是由ARC自动运行的,但是为了更好地理解,我在这里写了详细的文章,介绍了如何编写适当的代码。 我在那篇文章中用代码示例介绍了以下内容: 使用Swift定义属性时,默认会应用强引用。 在Swift中几乎所有地方都使用了强引用。 类的每个新创建的对象都有引用计数器。 将值的属性分配给对象后,它将增加。 在引用计数器的值大于0之前,它不会被释放。 它允许创建实例,但不增加ARC的引用计数。 大多数情况下,参考标记应被标记为较弱,并且比其他类型的参考具有较短的寿命。 如果将其引用设置为nil,则应使用弱引用。 如果没有其他实例强烈引用该实例,则实例将取消分配。 就像弱引用一样,保留计数器不增加1。 与弱引用不同,无主不必是可选的,因为在解除分配时它们不会自动设置为nil。 仅当您知道该实例的对象永远不会为零时,才应使用无主引用。 注意:只要您知道弱引用会在某个时候变为零,就可以使用它。 当您知道其引用一旦初始化就永远不会为零时,使用无主引用。 最后,如果您不管理内存,那么它会使您的应用程序不稳定,并导致大量内存泄漏。 但是通过谨慎地使用弱者和无人者,我们可以管理内存泄漏并放弃内存。 最初发布在 www.logisticinfotech.com

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() 做{ […]

Swift中的原型设计模式

通过复制现有对象的所有属性并创建独立的克隆,原型模式用于实例化新对象。 当新对象的构造效率低下时,此做法特别有用。 想象一下,下面有一个SmartPhone类: 现在我们需要创建此类的5个实例,如下所示: 我们可以很容易地意识到许多实例具有相同的属性,因此我们经常复制代码行,然后以不同的方式编辑任何属性。 没关系,但不是经过优化且容易出错。 让我们尝试将Prototype模式应用到下面的SmartPhone类中: 我们声明一个带有默认可选参数的克隆 func与属性相同。 该函数通过复制现有实例的所有属性返回一个新实例,然后根据需要修改某些属性。 现在创建5个实例作为波纹管: 我们不再需要通过调用设计的初始化程序来初始化新实例,只需“克隆”当前实例然后对其进行修改! 就这样! 原型模式非常易于理解,也易于通过其他编程语言实现。 当新对象的构造效率低下时,此功能特别有用。 如果您有任何疑问,请留下您的赞赏,感谢您的阅读!

Swift和iOS良好做法#12中代码质量和简洁性的提示

导入SomeExternalFramework FooViewController类:UIViewController,FoobarDelegate { let foo:富 private let fooStringConstant =“ FooConstant” 私人让floatConstant = 1234.5 // MARK:生命周期 //自定义初始化程序转到此处 // MARK:查看生命周期 覆盖func viewDidLoad(){ super.viewDidLoad() // … } // MARK:布局 私人函数makeViewConstraints(){ // … } // MARK:用户互动 func foobarButtonTapped(){ // … } //标记:FoobarDelegate func foobar(foobar:Foobar,didSomethingWithFoo foo:Foo){ // … } // MARK:其他助手 私人功能displayNameForFoo(foo:Foo){ // … } } 如果您不打算对一个类进行子类化,请将其定为final 。 对tableview进行两个扩展 (一个用于数据源,另一个用于委托方法)。 […]

为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 […]

在Swift-4中玩闭包(Part -2)

大家好 !! 在上一篇文章中,我们都讨论了Swift中的一些基本闭包。如果您尚未对其进行检查,请进行检查。在本教程中,我们将讨论更多内容。 Swift会自动为内联闭包提供简写参数名称,可用于通过名称$ 0,$ 1,$ 2等来引用闭包参数的值。 速记参数名称 正如我们上面讨论的,Swift 4通过表示$ 0,$ 1,$ 2-$ n来方便用户将内联闭包表示为速记参数名。通过在闭包表达式中使用此速记参数名,我们可以从其定义中省略闭包的参数列表。 in 关键字 由于闭包表达式完全由其主体组成,因此可以省略。请看以下示例。 因此,在第一个示例中创建了一个闭包,该闭包采用单个参数并返回字符串。此处$ 0表示第一个参数。类似地,在第二个示例中,闭包采用两个参数,通过使用$ 1,我们引用了第二个参数。关闭 自动关闭 我们知道闭包可以用作函数中的参数。当我们编写@autoclosure时 ,参数会自动包裹在闭包中。但是,如果我们创建一个具有@autoclosure的函数,则存在一个问题,通常调用该函数具有自动关闭功能的函数,但是实现这种功能并不常见。 让我们举一个小例子。 func simpleFunctionwithoutAutoclosure(_ parameters:()-> Void){ 打印(“嘿,我们刚刚创建了一个没有@autoclosure属性的函数”) 参数() } simpleFunctionwithoutAutoclosure({ 打印(“ hello”) }) func simpleFunctionwithAutoclosure(_参数:@autoclosure()->无效){ 打印(“嘿,我们刚刚创建了一个具有@autoclosure属性的函数”) 参数() } simpleFunctionwithAutoclosure(print(“ hii”)) 并且输出如下 从上面的两个函数中,我们注意到,在@autoclosure的情况下,无需将表达式用大括号括起来。 如果要传递闭包而不是自动闭包,这就是我们需要做的。 逃逸关闭 当闭包作为函数的参数传递给闭包时,闭包被认为是对函数的转义,但是在函数返回后会被调用。 声明将闭包作为其参数之一的函数时,可以在参数的类型之前编写@escaping,以指示允许对闭包进行转义。 Apple的文档给出了一个示例,该示例将传递给函数的闭包附加到您的类/结构中可变的闭包数组中: varcompleteHandlers:[()->无效] = [] func someFunctionWithEscapingClosure(completionHandler:@escaping()-> Void){ […]

Swift:forIn和forEach循环!

Swift提供了各种类型的循环进行迭代。 即使对于正在学习编程语言的新开发人员,也很容易理解和使用。 在这里,我想描述两种类型的for循环 ,乍一看似乎很令人困惑。 它们的工作方式相似,但是两者之间存在一些基本差异。 我在WordCount对象的函数中都尝试过。 下面是操场的快照。 如果您在操场上方看到直升机视图,则表明这两个for循环之间完全没有区别,以访问或循环访问数组的元素。 这是使用forIn和forEach的两个区别! 1)您不能使用break或Continue语句退出当前的闭包调用或跳过forEach循环中的后续调用,但可以在forIn循环中执行此操作。 2)在ForEach循环中使用return语句仅针对闭包中的当前调用退出,不会跳过后续调用,但ForIn循环也退出所有后续后续调用。 和上面的操场一样, forEach跳过了单词“ two”的打印语句的执行,这意味着它不会超出printByForEach函数。 而forIn跳过了所有随后的print语句的执行,这意味着它不在printByForIn函数中。 快乐编码,继续!!!

设置一个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”)作为目标(在项目的构建目录中); 将基于设备的框架的结构复制到新目录中; […]

用户关闭本地通知后会发生什么?

TLDR:如果将本地通知设置为在用户关闭本地通知权限时触发,则该通知仍会在预期的时间触发(如果用户稍后打开权限)。 本地通知是任何iOS开发人员工具箱中的有用工具。 如果您要构建任何类型的警报工具,则几乎没有其他选择。 不幸的是,许多用户无法区分本地通知和推送通知,并且会拒绝两者的权限。 最近,我正在开发一个应用程序,用户可以在其中注册以获得自己喜欢的事件的警报。 即使用户不允许我发送本地通知,我仍将其设置为在所需时间重复(我不会讨论如何设置本地通知,但这是苹果公司有关如何设置它们的说明)。 那么,那些发送给用户的本地通知怎么了? 更重要的是,如果我说服用户打开权限,通知是否会按计划发送? 让我们设置一个场景: 当用户拒绝了通知授权时,我将本地通知设置为每天2:00 PM重复。 下午1:30,用户授予我发送本地通知的权限。 下午2点会发生什么? 通知是按计划发送的,还是因为初始化时没有权限而从未设置? 在上述情况下,即使我在用户关闭通知的情况下设置了通知,通知也将照常发送。 由此看来,可以肯定地说,如果用户的权限仍然处于脱机状态,Apple只是抑制了您发送的通知。 希望这可以节省一些时间! 非常感谢您的阅读! 如果您喜欢这个故事,请在 Twitter上 关注我,在 那里我发布有关产品管理,工程和设计的文章。

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

在我正在从事的项目中,我们将代码分配拆分为多个小模块(框架),其中一个用于请求唯一标识符(在服务器端生成),该标识符将在每个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