Tag: swift

Swift内存布局简介

在上一篇文章中,我们讨论了Swifts 值类型语义的一些功能。 今天,我们将看一下如何分配不同的Swift类型以及这对我们的应用程序性能意味着什么的基础知识。 一个简单的类是Reference Type ,就像上一篇文章中提到的那样。 它具有一些我们大多数人都很早就了解的功能。 例如,单个类对象可以被多个变量引用和操纵。 但是,当我们创建一个类的实例时会发生什么呢? 类MyClass { var a:整数 init(a:Int){ self.a = a } } var A = MyClass(a:1) 上面的示例提供了一个简单的类,使我们可以开始研究创建引用类类型的变量A时发生的情况。 当我们调用MyClass初始化程序时,将进行一次调用以分配足够的内存以将我们的对象存储在内存中,在这里我们需要查看主内存的两个非常重要部分的第一个,即The Heap 。 堆是我们内存中用于动态分配的一部分。 这意味着如果在运行应用程序时需要即时创建一个新的引用类型对象,则需要在The Heap上请求空间。 由于内存的这一部分需要能够一次为多个线程提供服务而又不破坏任何数据,因此还需要一些机制来避免两次分配相同的内存块并处理并行分配调用。 在不详细介绍如何进行管理的情况下,让我们继续进行以下假设,即这实际上需要花费一些时间。 一旦找到足够的内存块并为我们分配了内存,我们的应用程序即可完成对对象的初始化。 除了初始化类中的实际值外,还需要初始化一些元数据值(其中包括类型数据和引用计数器)。 Swift使用一种称为自动引用计数(ARC)的方法来跟踪实际使用的对象。 如果某个对象未被任何变量引用,则可以安全地将其删除,并且可以将存储块返回以用于其他用途。 这是一个很棒的功能,但是它伴随着每次创建或共享对象时更新计数器的开销。 通常,如果您只是分配一个新对象,那么花费的时间就不会引起您的注意。 但是,如果您的程序不断创建这样的新对象,那么成本将会增加,并且您最终可能会浪费本来可以更好地用于其他用途的资源。 正如我在上一篇文章中提到的那样, struct和enum (以及其他)都是Value Types 。 我们需要问自己的问题是:将在哪里分配值类型? 这部分会有些棘手。 让我们首先看一下堆栈 -两个重要的主内存部分中的第二个。 堆栈是内存的一部分,它从其操作方式中获得名称-就像堆栈一样。 这个想法是,您有一堆数据,如果您添加任何新数据,它将被添加到顶部。 删除数据也被限制在内存空间的顶端,因此我们只能删除当前放置在顶部的数据。 系统使用一个简单的指针来跟踪当前堆栈内存顶部的位置。 这意味着分配和取消分配内存是通过简单的增量或减量操作完成的,因此非常快。 不利的一面是,这种结构与The Heap可以提供的动态分配类型不太兼容。 […]

如何将动态Swift框架添加到命令行工具

让我们逐步介绍如何尝试向命令行工具中添加动态框架,并讨论每步操作中出了什么问题。 步骤1:将其添加到“链接的框架和库”部分 这是您运行应用程序时发生的情况: dyld:库未加载:@ rpath / libswiftAppKit.dylib 引用自:/Users/seanberry/Library/Developer/Xcode/DerivedData/TestCommandLineTool-fnrmhjvjmugvqueaqvbklzwhqvuv/Build/Products/Debug/ThirdParty.framework/Versions/A/ThirdParty 原因:找不到图片 ThirdParty.framework尝试在@rpath目录中找到libswiftAppKit.dylib (它是Swift标准库的一部分)。 我们可以看到ThirdParty.framework如何通过运行来定义@rpath $ oTool -l ThirdParty.framework / Versions / Current / ThirdParty 加载命令27 指令LC_RPATH cmdsize 48 路径@executable_path /../ Frameworks(偏移量12) 加载命令28 指令LC_RPATH cmdsize 40 路径@ loader_path / Frameworks(偏移量12) 好吧,开枪。 这些与我们的命令行工具无关。 我们没有任何名为/ Frameworks或../Frameworks的文件夹。 为什么要在其中寻找Swift标准库? 因为它是为iOS和Mac应用程序构建的。 这是Mac应用程序中的目录结构: 那解释了path @executable_path/../Frameworks 对于iOS,应用程序内部的目录结构为: 这说明了path @loader_path/Frameworks (offset 12) 但是,谦虚的命令行工具开发人员呢? Swift标准库在我们的可执行文件中静态链接,但是我们的第三方框架找不到它们。 不幸的是,它们并没有存储在每台Mac上的标准位置。 开发人员可以访问埋在Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx […]

使用懒惰延迟计算

作为iOS开发人员,您可能已经听说过用于初始化的lazy关键字-除非有人真的想要与之交互,否则不会创建惰性组件。 那真lazy 作品:推迟工作直到需要做为止。 实际上,我们可以做更多的事情。 不仅用于属性初始化,还用于Swift函数编程中的计算。 让我们看看它是如何工作的。 假设我们有一个由整数组成的数组,并且我们要求结果的值是原始数组的一个元素的两倍。 这是示例代码: 让数组= [1,2,4,5,3,7] let element = array.map {$ 0 * 2} [3] 打印(元素) 您可能会注意到,我们只需要第3个元素,而我们将数组中所有6个元素的值加倍,这是多余且无用的。 如何解决? 使用lazy 。 Swift提供了一个名为LazySequenceProtocol的协议   ,并且在其扩展名中有一个惰性变量来推迟计算(例如map 和filter 在函数式编程中。 定义如下: ///避免创建多层“ LazySequence”包装器。 ///符合“ LazySequenceProtocol”的所有内容都已经是懒惰的。 扩展LazySequenceProtocol { ///与`self`相同。 public var lazy:自我{得到} } 随着lazy   ,我们可以修复原始代码以使其高效: 让数组= [1,2,4,5,3,7] 让element = array.lazy.map {$ 0 * 2} [3] 打印(元素) […]

使用依赖注入来测试UIViewController

大家好,当我们开始编码以创建需要其他对象才能工作的对象时,这是很常见的,例如在Car类中,需要Person对象来启动引擎和驱动器( starEngine和drive是需要Person实例的假设方法)。 所以我们可以说Car需要一个Person来工作。 上面的代码向我们展示了Jhon正在驾驶我们的汽车,只有Jhon可以做到! 因为每个Car对象都会创建一个名为Jhon的Person的实例。 但是,如果玛丽想开车怎么办? 我们如何重写该代码以让Mary开车? 我们可以将一个Person传递到我们的Car ,使其可用于Person任何实例,换句话说:可重用。 我们不在乎如何创建Person对象,如果它是由工厂,另一个类创建的,或者它需要名称,年龄或任何其他依赖关系,我们只需要一个Person实例即可。 在软件工程中, 依赖项注入是一种技术,通过该技术,一个对象(或静态方法)可以提供另一个对象的依赖项。 依赖项是可以使用的对象(服务)。 注入是将依赖项传递给将使用它的依赖对象(客户端)。 让我们把这个例子转为日常问题。 在下面的代码中,我们的ViewController使用ListService对象。 这个ListService从Web服务加载数据,但是如果我们想从本地数据库,文件或其他地方加载数据怎么办? 我们需要创建另一个ViewController吗? 如果我们要测试此ViewController如何使API响应始终保持相同,以便可以验证测试? 现在考虑对此类进行测试,每次运行测试时,我们至少需要Internet连接和稳定的响应。 这使我们的测试变慢且不可行。 解决方案中使用依赖项注入来使用自定义的模拟ListService对象。 一种实现方法是创建一个具有load方法的接口,并在自定义对象中实现它。 换句话说,我们创建了Service协议和对象,它们知道如何从Web服务器,数据库,文件等中加载数据。 通过这种方法,我们可以轻松创建要使用的各种Service 。 例如,一个服务从Web服务加载数据,第二个服务从本地数据库加载数据,最后一个服务被模拟,因此我们可以使用它来测试ViewController而无需真正的API响应或本地数据库中的数据。 每种Service对象都可以具有唯一的依赖关系。 我们的WebServiceListService将需要知道如何发出请求,因此将需要一个Request对象。 DataBaseListService需要数据库连接才能加载数据。 这些独特的依赖关系对于我们的ViewController是不可见的。 它只需要一个具有load()方法的Service对象。 要测试我们的ViewController我们只需要创建一个MockListService并在测试期间将其注入即可。 注入对象使我们的代码解耦并且更易于测试。 这可以通过构造函数,setter或接口传递对象来实现。 附:如果您喜欢这篇文章,请在Twitter上分享,或在中级推荐,或两者都=)。 这确实有助于我吸引更多人。 非常感谢。

使用Swift 3.0.2的iOS自定义活动指示器

活动指示器是一个旋转的轮子,指示任务正在处理中。 如果某项操作需要花费明显且不确定的时间来处理(例如CPU密集型任务或连接到网络),则应显示活动指示器,以向用户保证您的应用程序不会停止或冻结。 如何使用: //Show activityIndicatorView customActivityIndi​​catory(self.view) 要么 customActivityIndi​​catory(self.view,startAnimate:true) //hide activityIndicatorView customActivityIndi​​catory(self.view,startAnimate:false) 类似于活动指标的元素 以下元素提供与活动指示器类似的功能: 进度视图。 代表进度条的类。 当您的任务需要一定时间时,请使用此类而不是活动指示器。 有关更多信息,请参见进度视图。 电子邮件:sourleangchhean168@gmail.com Stackoverflow:酸辣豆蔻 参考: https : //developer.apple.com/library/content/documentation/UserExperience/Conceptual/UIKitUICatalog/UIActivityIndi​​catorView.html

Xcode构建方案和构建配置的一些实际用途(快速)

您是否曾经想为iOS应用的免费版和付费版使用完全相同的代码库? 您的客户是否同时具有需要与相同代码交谈的开发服务器和生产服务器? 您是否需要为团队中的测试人员创建应用程序的内部临时构建? 如果您曾经对以上任何一个问题回答“是”,则听起来您需要自定义构建方案。 我希望我早日发现了Xcode构建方案的强大功能。 作为开发人员,他们使您能够通过针对不同环境的细微调整来交付相同代码的不同版本。 一旦学习了如何使用它们,您也会爱上它们。 使用自定义构建方案,您可以 编写仅在您的应用的免费版本上运行的代码,从而使您可以展示广告或提供应用内购买,而无需复制目标或项目文件。 在开发环境中测试您的应用程序后,轻击一个开关以提供与生产服务器通信的构建。 构建并分发一个内部应用程序,您可以将其部署到团队中的测试人员。 TL; DR构建方案将为您节省大量的时间。 使用构建配置来创建应用程序的免费版本 数字在里面。不管我们喜欢与否,最赚钱的应用程序是免费提供的。 大部分资金用于展示广告和销售应用内购买。 这意味着,如果您想经营一家盈利的iOS应用业务,则可能需要提供应用的免费版本。 我第一次听到此消息后自然感到后退。 我没有涉足这个行业来销售广告。 我之所以加入它,是因为我想创造出我想使用的漂亮产品。 出售“您祖母摆脱腹肌的怪异小技巧”的丑陋横幅使我的优雅设计变得模糊不清的前景让我感到有些不安。 坦白说,它仍然如此。 通过告诉自己,只要我在付费版本和免费版本的应用程序之间做出选择,我就设法证明广告的合理性,这并不是犯错设计。 如果有足够的人喜欢免费版本,它将带动更多人使用付费版本。 现在,我可以在晚上入睡了,构建计划对此负有部分责任。 Build Schemes很棒,因为它们使您能够编写仅适用于应用程序免费版本的代码 (如果您购买的某些应用程序仅适用于付费版本,则为付费版本)。 过去,我为此而苦苦挣扎,尝试了各种骨头问题。 我做的一些幼稚的事情浪费了很多时间 在我的一个项目中,我创建了两个单独的目标,一个针对付费版本,另一个针对免费版本。 这实际上是可行的,但最终的工作量远远超过了需要的工作量。 确实在开发初期,我实际上只是为免费版本复制了所有源文件。 我不需要告诉你为什么这是一个可怕的主意。 从我的错误中学习,不要做任何一个! 阅读本文并按照以下步骤操作。 最终结果将更加易于管理。 构建方案和构建配置之间的区别 当我开始iOS开发时,我不知道什么是构建方案。 毕竟,默认情况下,大多数应用仅使用单个构建方案。 我认为真正阻碍我对构建方案理解的一件事是开发构建和发布构建之间的另一区别。 我以为这些是不同的构建方案,但实际上它们是不同的构建配置 。 构建方案是整个构建过程的蓝图,它是一种告诉Xcode您要用于给定目标(框架或应用程序包)创建开发,单元测试和生产构建的构建配置的方式。 构建配置是可以应用于任何目标的一组特定的构建设置。 大多数应用程序项目带有两种构建配置和一种构建方案。 您将获得调试和发布构建配置以及运行调试配置以进行调试的构建方案以及用于归档/提交的发布配置。 对于大多数项目,这是完全可以的,不需要进行任何调整。 但是,如果您想同时提供同一应用程序的免费和付费版本,那还远远不够。 添加新的构建配置 要制作免费版本的应用程序时,需要先添加新的构建配置。 我希望这会更容易,但事实并非如此。 这就是为什么我要带您了解它的原因。 打开Xcode,然后选择项目文件。 现在待在你身边! […]

我的第一个IOS应用程序:DoctorMe和我

“ DoctorMe”เป็นแอปพลิเคชันหนึ่งสำหรับการดูแลสุขภาพเบื้องต้นงต้นiosและandroidถ้จะถาจะถามความผูกผันมผูกผันมากับแอปนี้คือี้คืานก็ได้ทำdoctormeเวอร์ชันsymbian(สมัยsymbian(nokia)ยังมีชีวิตอยู่ viอกับเค้าviนานเหลือเกินฮ่าๆ)viอนนั้นยังไม่ได้ลงovi商店 งามพิเศษของdoctormeที่เราจะเขียนวันนี้คือ “这是我的第一个iOS应用程序” meริงๆก็คิดว่ราก็คิดว่าเราควรเขียนแอปนะความรู้สึกคือเวลาได้เขียนแอปมันควบคุมและเล่นได้ตอนฝึกงานเราทำdoctorme-symbianรู้สึกมีความสุขมากกับกากกับการเขียนแอปแต่พอเข้ามาทำงานก็เป็นช่วงที่ กับราคิดว่าไม่อยากเขียนแอปแล้วไปเล่นกับ服务器ดีกว่าไปๆาๆคิดว่าไม่น่ารอดฮ่าๆ doctorองกลับมาเขียนแอปดีกว่าDoctorme-androidสักพักแล้วก็หนีไปเป็น顾问อยู่ช่วงหนึ่งู่ช่วงหอู่ช่วงหาว! doctorาเขียนdoctorme-iosดีกว่า(เป็นช่วงชีวิตที่งงๆเหลือเกิน)ก็ชอบไงก็ต้องกลับมาทำดิ ทำอกลับมรกลับมรทำริงๆรกจริงๆxcodeใช้ยังไง? เริ่มยังไง? 设计ทำตรงไหน? ตั้ง项目结构 swยนswiftยังไง? นี่คือคำถามในหัวตลอดว่า“จะรอดเหรอ”ฮ่าๆแต่ยังไงก็ต้องรอดเนอะ!! ารรอดก็คือซื้อรคอต้า(การลงทุนต้องมา) udeดีช่วงดีช่วงude 300 300 300 300 300 300 300 300 300 300 300 300 300 300 300 300ก็เล300 300 300 300 300 300 300 300มบ้ androidมาก่อนก็จะตั้งstructureๆีกแบบหๆๆๆๆแบบแต่ละแบบแต่ละแบบแต่ละก็จะตั้งแบบแต่ละแบบแต่ละีกแบบหีกแบบหีกแบบหีกแบบหีกแบบหีกแบบหีกแบบหีกแบบหณณณณณณVC VC แบบหนึ่ง กทำายก็เหลืออันที่ใกล้เคียงกับที่เราทำเนื่องจากทำdoctorme-androidมาก่อนก็ไม่อยากให้หนีกันมากเพราะว่าเวลาแก้า่น่าจะสะดวกกว่านะ structureรื่อง项目结构คิดว่าแล้วแต่คนชอบแล้วกันเอาที่สะดวกเนอะ?! cocopodคือตัวที่เอาไว้import libข้างนอกมาใช้ในprojectเรางาเทียบกับandroidแล้วเจ้าีกัcocopodก็คือgradleไม่หนไม่หนมากใช้ง่ายเหมือนกันios ๆ ทำรื่องเบลอสุดน่าจะเป็นตอนทำdesign xยxcode ทำอดีของการทำdesignบนนี้คือชอบส่วนของStoryboardสุดๆเห็นแล้วอิจฉาเลยandroidน่าจะมีแบบนี้บ้างดูแบ​​บเห็นภาพรวมของแอปเลย code xcode codeา้าๆกกกกกน้า layoutนที่หนักใจสุดคือตอนทำauto […]

Swift 4.0教程的核心数据

核心数据 -核心数据是用于管理应用程序中的数据模型层对象或实例上下文的框架。 它为与对象生命周期和对象图管理(包括持久性)相关的常见任务提供了通用的自动化数据存储解决方案。 选通启动Goto Xcode并在单个视图上创建New iOS Project。 项目名称CoreDataSwift 在“界面”构建器中单击Main.Storyboard,然后单击项目导航编辑器-嵌入-导航控制器。 然后,单击导航ViewController之后,然后将TableView拖到ViewController中。 使TableView viewcontroller出口代理,数据源并导入CoreData ViewController类:UIViewController,UITableViewDataSource,UITableViewDelegate { 覆盖func viewDidLoad(){ //加载视图后进行其他任何设置,通常是从笔尖进行。 覆盖func didReceiveMemoryWarning(){ super.didReceiveMemoryWarning() //处理所有可以重新创建的资源。 下一个IBOutlet属性TableView UITableView是tableView并注册tableView笔尖viewDidLoad @IBOutlet弱var tableView:UITableView! 覆盖func viewDidLoad(){ tableView.register(UITableViewCell.self,forCellReuseIdentifier:“单元格”) //加载视图后进行其他任何设置,通常是从笔尖进行。 现在我们将选择函数UITableViewDataSource func numberOfSections(在tableView中:UITableView)-> Int { func tableView(_ tableView:UITableView,numberOfRowsInSection部分:Int)-> Int { func tableView(_ tableView:UITableView,cellForRowAt indexPath:IndexPath)-> UITableViewCell { 让人=人[indexPath.row] let cell = tableView.dequeueReusableCell(withIdentifier:“ Cell”,用于:indexPath) cell.textLabel?.text = person.value(forKeyPath:“ name”)as? […]

许多面孔的VIPER —第4部分:EventEmitter iOS演示

正如在第3部分中所宣布的,现在该展示我们如何通过使用Event Emitters使VIPER客户端体系结构变得更加复杂和宽容。 我太好了……很抱歉让您失望,但这就是我们漫长的传奇故事的全部代码:😧 3个事件,其中有4个负载项,最后一个事件为2:一个用于PaymentsModule ,另一个用于AnalyticsModule 。 花一些时间,并通过此示例查看存储库。 尝试弄清楚这种方法如何为您的案件提供帮助。 第1部分中解决的问题似乎可以很好地解决。 您可能会问为什么使用此功能,为什么不使用RxSwift或类似的功能? 好吧,一旦您开始使用FRP , FRP就会变得更加艰难,更加坚强,而且非常占主导地位,并且由于这个原因以及许多其他原因,不幸的是,它们在开发人员之间也存在分歧。 本系列文章中介绍的方法(尤其是在最后一部分)非常精简,可以随时根据需要进行更改。 同样, 基于事件的方法比响应 式方法更容易理解,尽管它们是核心。 对于可能发现反应式方法有些吓人的开发人员,这可能是完成其工作的好方法。

[String:String]与NSDictionary

我在Swift中与字典的斗争故事 嘿! 欢迎来到我2019年的第一篇技术博客文章! 😄 所以我有一个从2018年开始从事的项目。 它涉及Firebase,我将其用作项目的数据库。 我正在挑战自己做一个Twitter克隆iOS应用程序。 我现在在哪里 所以现在,我有了一些固定的东西。 我已经注册,登录,标签栏,撰写屏幕以及数据。 好吧,一些数据。 它看起来像这样。 我接下来要做的是在时间轴或供稿中显示该推文。 因此,我创建了一个UITableViewController屏幕。 所以这是有趣的地方。 问题 自然,我会这样做。 给定上面所示的数据库结构,这将起作用。 考虑到每个快照都由一个单独的tweet id作为键,并且值是[String : String]的字典,该字典是[“tweet_content” : “some stuff”] 。 除了它没有用。 显然,Firebase更改了当您通过snapshot.children进行迭代时返回的数据类型。 经过一些谷歌搜索,我发现您应该使用snapshot.children.allObjects并将其FIRDataSnapshot为FIRDataSnapshot数组。 因此,遵循这些思路。 您可能会说,由于我现在使用数组,因此不得不更改一些代码。 这可行。 它实际上返回了tweet_content值,但这与我描述代码的方式不完全相同。 这是获取价值的有效方法,但这种怪异的方法,或者至少不是我习惯的方法。 也许它不像我预期的那样可读。 如果您想知道什么是dict?.values输出,就是这个, [“tweet_content” = “Hello there”] 因此,我试图找到另一种方法。 我终于找到了解决方案 因此,当我在学校时仍想弄清楚JSON的时候,我回头看了看我可信赖的旧代码。 我看到我使用了NSDictionary而不是[String : String] 。 所以我尝试了。 瞧,它确实起作用了。 这是代码。 这行得通,而且可读性强得多。 尽管事后看来,我可以不必指定allObjects并将其强制转换为FIRDataSnapshot数组。 也许Swift的[String : String]和NSDictionary的实现略有不同? […]