更新:添加了附件图像和附件视图🙂 大家好! 这是我的第一篇中篇文章,所以希望对此做出有趣的贡献。 😉 如果您使用过Swift和/或UIKit iOS框架,则可能曾经想过显示警报,并可能使用过UIAlertController 。 事实是,此类不是非常可定制的,您几乎不能更改其色调颜色,并且不能做更多的事情…… 因此,我开始研究如何使其变暗或更改字体……但是我意识到最好的方法就是制作自己的警报 。 话虽如此……与Apple私有API或内部值:D混在一起仍然真的很酷,因此,这只是一堆Swift’hacks’,很有趣,可以使UIAlertController更可定制。 发出上述警报的代码很简单: 但是什么是DarkAlertController? 只是CustomizableAlertController的子类。 如此简单, CustomizableAlertController具有视觉效果的属性,以及一些可以轻松更改标题和消息的文本属性的属性。 (您可以在github中查看完整的实现)。 您还可以像这样轻松更改警报背景: alert.contentView?.backgroundColor = .red 如何设置标题和消息文本属性? 只需使用KVC更改属性即可: 警报。 setValue (newValue,forKey:“ attributedTitle ”) 警报。 setValue (newValue,forKey:“ attributedMessage ”) 警报动作归因于文本? 有点棘手; 您首先需要标签,然后使用attributedText属性: var标签:UILabel? { 回报(自我。 值 ( forKey :“ __representer ”)为? NSObject)? 。 值 ( forKey :“ label ”)为? UILabel } […]
通过 谢尔盖·沙巴林 ( Sergey Shabalin) 假设您有一个运行在主线程上的移动应用程序,负责执行操作UI的代码。 每当您在应用中打包一些耗时的代码(例如从Web上下载或在主线程上进行图像处理)时,这都会显着降低UI性能,甚至可能导致其完全死机。 iOS中的多线程 那么有没有办法改变应用程序的架构,使此类问题永远不会发生? 我相信并发在这里可以提供帮助,因为并发能够执行两个或多个独立任务,例如计算,从Web或驱动器上下载数据,图像处理等。 但是,这并不是免费的,随着并发性的引入,代码线程安全性可能会在执行中受到损害。 一旦允许任务同时执行,就为任务可以访问相同资源的问题做好准备,例如更改不同线程上的相同变量或访问已被其他任务阻止的资源。 这最终可能导致拆除在不同线程上使用的那些资源。 在iOS开发中,并发用于提高生产力和UI响应能力,这是由Thread,GCD(中央总调度)和Operation等多种工具提供的。 可以肯定地说,在Swift 3出现之前,强大的GCD框架正在使用C API,这为用户操作带来了很多隐患。 Swift 3改变了一切。 GCD获得了一种基于GCD逻辑的易于使用的新语法。 为了更好地了解如何使用并发,让我们找出哪些关键概念与GCD和Operation工具一起使用。 基本概念是队列 。 因此,从开发人员的角度谈论iOS并发时,很可能会提到队列。 队列中有闭合的队列,并根据指定的顺序,系统将它们一个接一个地拉,然后将它们部署在适当的线程上。 队列在构成并发模式的多个线程中遵循FIFO(先进先出)原则。 串行队列与并发队列 队列可以是: 串行或连续,当队列顶部的闭包被iOS拉出并运行直到结束时,再拉出另一个队列元素,依此类推。 并发或多线程,当系统在队列顶部拉一个闭包并在某个线程中启动其执行时。 如果系统有权访问更多资源,则它将从队列中选择下一个元素,并在第一个功能仍在工作时在另一个线程上启动它。 这样,系统可以提取许多功能。 同步方法与异步方法 创建队列后,有两种将作业放入队列的方法: 同步方法表示与当前队列有关的同步任务放置。 整个方法完成后, sync方法将控制权返回到当前队列,从而阻止了当前队列。 异步方法是与当前队列相关的异步任务布置。 与sync方法相反, Async在另一个队列上启动任务后立即将控件返回到当前队列,而无需等待其结束。 因此, 异步方法不会阻止当前队列上的任务执行。 可能会出现以下不同的队列 : 如果是异步执行方法, 则为 串行队列;如果是同步执行, 则为并发队列。 并发队列。 开发人员的任务完全取决于队列选择,并在同步方法的帮助下将任务(封闭)同步添加到队列中,或通过异步方法异步添加到队列中。 iOS从那里获取它。 全局调度队列 除了定制的用户队列之外,iOS还提供了一些五种现成的全局调度队列: 主队列。 负责所有UI操作: […]
我和我12年级的学生最近在“ Swift应用程序开发入门”课程(教师)(学生)中完成了本年度最有趣,最愉快的课程:第13课-问题机器人。 这是我学生创造应用程序的第一个机会,其作用远不止是展示图片或类似内容的单一视图,就像我们在第5课中所做的那样。第5课很重要,因为它允许我的学生开始学习如何使用Xcode; 但是,我们实际上并没有创建具有任何实际功能的应用程序。 Bot问题使我的学生有机会创建[1]功能齐全的应用程序,他们喜欢它! 课程介绍 我主要按照《 Swift老师指南的应用程序开发入门 》和《 Swift Student的应用程序开发入门》一书中的教学计划和课程指导进行学习 。 首先,让我的学生们告诉我他们最喜欢的应用,然后在他/她的iPad上的Classic Explain Everything中写下该应用的名称。 然后,我们讨论了模型视图控制器(MVC)应用程序设计架构/模式。 然后,我让每个学生创建一个图表,说明他们最喜欢的应用程序的各个部分适合MVC模式的位置。 我使用了建议的示例,说明了Apple Notes应用程序如何在图表中使用MVC设计。 然后,我的一些学生决定选择另一个更易于绘制的应用程序。 我们对控制器如何真正成为许多应用程序的“大脑”以及如何处理从模型到视图提供大量数据的“繁重工作”进行了非常精彩的讨论。 然后,我们的讨论着眼于如何将AI引入该模型中,以扩展和自动处理对用户请求的回复。 总的来说,我认为这是我本学年与这些学生一起使用的最好的课程介绍。 他们喜欢分析自己喜欢的应用程序的MVC模型,并在此过程中获得了很多知识。 进入守则 接下来,我们打开questionbot.xprodproj文件,并查看了所有文件。 然后,我们打开QuestionAnswerer.swift文件,因为这是我们应用程序的控制器或“大脑”文件。 我让学生看了一个非常简单的结构,该结构包含responseTo(question: String)函数,该函数将为用户提供对他/她的问题的响应。 然后,我让我的学生在模拟器中运行该应用程序,然后问他们想问的任何三个问题。 我们发现,对于每个询问的问题,应用程序均返回“?”的答案。 我问我的学生,如果我们都得到相同的简单答案,那么这是否一定是该应用程序当前状态的限制。 我希望我的学生可以直接转到QuestionAnswerer.swift文件,并发现responseTo(question: String)函数包含单个return语句,该语句始终对所问的任何问题给出“?”。 几乎每个学生都直接进入该确切的文件和功能,并发现应用程序在其当前状态下的“?”返回限制。 现在是时候为我们的应用程序创建一些自定义答案了。 我们启动了QuestionAnswerer.playground文件,并一起完成了该课程。 这是我最喜欢的带有Swift的应用程序开发入门课程的一部分-学习,探索和制作Swift操场文件中的代码原型。 通过让学生在Swift Playground中创建responseTo(question: String)函数,我们能够比在Xcode项目文件中更快地创建可以正常工作的函数。 Swift操场文件立即编译并为我们提供代码结果; 因此,我的每个学生都能够立即看到代码的结果,以便他们可以决定自己需要做什么才能获得给出预期结果的功能。 我相信这是本课程的最大优势–能够将复杂的项目呈现在简单的学习环境中,使学生更容易理解。 整理机器人 一旦我的学生完成了他们的responseTo(question: String)函数并粘贴到QuestionBot Xcode项目的QuestionAnswerer.swift文件中,我们便可以做出一些设计决策。 我向学生展示了如何更改背景和按钮的颜色(提示:属性检查器)以及QuestionBot的表情符号。 然后每个人都在模拟器中运行该应用程序以检查以确保我们获得了预期的功能。 我们做到了。 然后我问我的学生,“更改您的QuestionBot以对其进行自定义有多困难?”我这样做是为了扩展本课,以便学生们想返回到QuestionAnswerer.swift文件来创建该应用程序的新版本。创建一些有趣,有趣或有用的东西,我们可以将它们加载到各自的iPad上,向他们的朋友展示。 这是本课中最好的部分。 我所有的学生立即进入代码中,以创建自定义版本的QuestionBot,以回答有关视频游戏,琐事或海绵鲍勃方形裤子(ugh)的问题。 我什至让一个学生记下她的笔记并创建一个QuestionBot来帮助她复习即将进行的政府考试。 […]
WebCash韩国的生活 我曾在一家位于韩国汉城的名为WebCash company的软件公司中居住了大约两年半。 以下是有关WebCash(http://www.webcash.co.kr/index_eng.htm)的信息: #1:前6个月担任IOS实习生 我没有与IOS技能相关的经验,但就在4个月前之前,我曾经学习过基于Java代码的AOS(Android),而该代码也确实与我学校的课程有关。 并添加在Android中用作接口的XML代码。 这意味着我从什么都不是IOS开发开始。 #1.1:从身体开始 我有一位韩国高个子的导师,戴眼镜。 他不像我那么帅。 哈哈哈… 我记得他都在谈论IOS开发,因此他给了我3本书。 他告诉我准备演示文稿,以便在每个星期五下午向他和整个团队展示。 经过4个月,我对IOS有了很多了解。 还有两个月的时间,我只是重做与IOS编程有关的旧团队项目。 #1.2:首次学习IOS时感觉还不错 您知道什么是韩国料理都很好,但是因为这是第一次体验韩国料理,所以让我非常恶心。 awww……。 有一次我永远不会忘记吃过午饭后,我会继续读书。在这段时间内,我可以看到iMac屏幕上的文字会随着海中的波浪移动。 我立刻起身去洗手间。 有时我的眼睛处于烹饪模式。 像是沸腾。 好热 我可以看到我的头发有些细线变成白色而没有突出显示颜色。 推动自己,因为没有其他人会为您做到这一点。 #2:开始加入真实项目 在6个月后,我的导师有时间允许我参与一个称为客户管理项目的真实项目(即将管理所有注册该服务的客户,并向他们提供有用的信息和一些更有用的功能)。 #2.1:不仅是iOS编程 上述项目结束后。 我对IOS开发感到很满意。 在这段时间里,我不仅在研究IOS,还研究了称为API的后端。 它允许许多平台通过一个API进行访问。 指向#2.2,您可以了解有关我的研究的更多信息。 #2.2:进行研究 在没有工作的情况下,我会对当今技术中的新事物和有用事物进行研究。 我发现一些像: 1 。 Yobi Git D2 Naver:像github这样的源代码控制器,使开发人员可以轻松地与团队合作。 注意:使用play框架安装我们的服务器 2 。 推送通知服务器:它可以在Web,aos,ios等平台上使用。 3 。 API:如何通过在每种编程语言上使用安全性库来制作安全性API。 4 。 OpenCV(图像处理):允许分析图像是哪个对象。 5 。 […]
VIPER是一种模式设计,代表了传统模式MVC(模型-视图-控制器)的替代产品,解决了控制器可以包含所有应用程序逻辑的问题,从而在组件之间产生了强大的耦合,并使难度更大。代码维护,例如使用MVC进行代码维护。 VIPER将应用程序逻辑的责任划分为多个组件,从而实现了更大程度的去耦以及更好的代码维护和测试。 这些组件将它们的名称命名为模式:(V)iew,(I)相互作用器,(P)ententer,(E)ntity和(R)outing或线框。 视图 VIPER中的视图是被动的。 他们向Presenter通知用户产生的事件,并期望他的响应与必须显示的数据。 视图负责了解如何显示数据和管理用户交互。 他们通过视图模型处理数据,其中包含必须显示的特定数据。 主持人 它们从视图中接收事件,并基于这些事件可以与交互器通信,以请求数据请求,或与路由或线框通信,以在应用程序中执行某些导航逻辑。 交互者回答后,演示者负责在业务模型(使用交互者)和视图模型(使用视图)之间执行转换数据。 转换后,它们将与视图通信,以通知要显示的视图模型。 演示者不知道如何构成视图。 互动者 他们负责执行所有业务逻辑。 他们使用业务模型或实体。 交互者必须处理来自演示者的请求数据。 因此,依次调用服务,数据库或在数据所在的任何地方搜索。 他们转换业务模型或实体中的数据。 处理完数据后,会将其提供给演示者。 交互者不了解用户界面。 实体 它们代表自己的应用程序业务逻辑数据,并由交互器处理。 路由 他们负责执行所有屏幕导航,进入应用程序。 路由也称为线框。 首先创建它们,它们自己负责创建其他组件:视图,演示者,交互者,并在它们之间建立关系。 它们接收主持人的请求,并负责在屏幕之间传输数据。 他们允许知道应用程序内导航的不同可能性是什么。 什么时候应该使用VIPER 当我们想要为我们的项目提供一个有序的结构,可以轻松,清晰地扩展并且可以重用时,您可以并行开发不同的组件而不会产生冲突。 VIPER促进了组件的测试,并且由于每个组件封装了不同的职责而可能产生的可能的bug。 何时不应该使用VIPER VIPER牵涉到许多组件的创建,如果您的项目很小并且您知道将来将无法扩展,那么这可能会带来不便。 另外,所有开发团队都必须完全了解VIPER,以避免与其他模式产生混合,这可能会妨碍项目的开发和维护。 例 我在这里留下一个在Swift中开发的小项目,作为具有VIPER模式的项目的示例。 希望对您有所帮助。 https://github.com/aortegas/VIPER_Example.git 请让我知道您对本文的看法,您的问题或产生的错误。 感谢您的反馈意见。 请享用! 阿尔贝托·奥尔特加(Alberto Ortega)
从概念管理器的依赖注入 (Inyeccióndedependencias)和依赖倒置 (Inversióndedependencias)中获取信息。 从遗漏的概念到美国,再到美国。 Imagina que tienes uncódigocomo este: 消费者依赖于基础数据库的数据 (包括具体的注释),而无需咨询任何产品。 消费者可购买的物品已被测试 。 Seríaalgoasí: ?Fácil,不? 布宜诺斯艾利斯,洛杉矶测试单位(Ademásde otrascaracterísticas)。 Imagina que nuestro objeto 数据库临时项目(tiene que leer del disco等…)。 实际生产的基础设施。 ¿Quéhacemos? 要在理想的情况下从数据库中删除数据库 ,请在问题上进行以下测试: 消费者在 数据库中存储的即时数据。 Para solucionarlo vamos a inectecta ladependencia (en este caso,构造函数中位数de la clase)。 Elcódigoquedaríatal queasí: 是依赖注入: 消费者的构造函数,即构造函数的遍历消费者和实例。 Ahora,Yapodríamoshacer lo siguiente en el测试: 佩罗…? 布宜诺斯艾利斯,布宜诺斯艾利斯 Podemos […]
在几乎每个应用程序中,都有一段时间我们必须进行一些格式化。 有时我们需要将Bool转换为可读的字符串,更经常的是将Date对象转换为文本文字,这对于使用我们的应用程序的人来说是可以理解的,而不是说用逗号/点号将数字四舍五入到两个空格(取决于国家/地区或操作系统设置)或在数字的千分之一之间放置分隔符。 Apple满足了这一要求,并创建了可在我们的应用程序中使用的格式化程序集。 苹果开发人员的意图是创建非常清晰的API,该API将是独立于国家/地区的,而且也非常可定制。 他们为此做得很好。 例如,要创建DateFormatter以在屏幕上的单个标签中打印不带时间的Date ,我们必须: var date:Date = // … 2001-01-02 func setupDate(){ 让dateFormatter = DateFormatter() dateFormatter.dateStyle = .mediumStyle dateFormatter.timeStyle = .noStyle dateLabel.text = dateFormatter.string(来自:日期) } 这将根据iOS或OS X语言首选项显示不同的字符串。 如果我们使用英语作为默认语言,它将显示Jan 2, 2001,对于法语,我们将显示2 janv. 2001 2 janv. 2001 ,对于日语,我们得到2001/01/02 。 其余的格式化程序具有非常相似的API。 我们可以使用枚举根据语言偏好来定义行为,但是我们也可以使用字符串格式来创建独立于系统配置的格式化程序。 当我们将日期作为字符串发送到REST服务时,我们可以将格式器定义为: func getCurrentDateStringForRest()->字符串{ 让dateFormatter = DateFormatter() dateFormatter.dateFormat =“ yyyy-MM-dd HH:mm:ss” 返回dateFormatter.string(来自:Date()) }
您好,我亲爱的开发人员, 我有个故事要告诉你。 从前我很无聊。 那时我像往常一样在课堂上玩耍,用猕猴桃为他们编写测试。 我偶然发现了一个有趣的问题,我真的很想为块模拟,以删除不必要的样板。 可悲的是,没有人开源。 所以我想,为什么不写呢? 具有一些非常有趣的功能的请求不会伤害我或整个社区。 因此,我开始实施代码,并在重构和挖掘运行时库的过程中发现了很多奇怪的事情。 可悲的是,故事并没有很好地结束,因为当我提交请求请求时,维护人员决定停止添加任何具有大型功能的新功能。 而且我就像FFFFFFUUUUUUUUUUUUUUUUUUUU…。因为在接受请求请求之前,我开始在项目中使用该Kiwi功能,这意味着我必须维护并行分支。 我的故事。 那好吧… 尽管如此,在这段旅程中,我发现代码中散布着一件有趣的事情: #if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG @尝试{ #endif // #if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG … #if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG } @catch(NSException * exception){ KWSetExceptionFromAcrossInvocationBoundary(exception); } #endif // #if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG 如果看一看,您会发现它分散在整个代码中,但是它具有清晰的模式。 对我们来说,这意味着应该删除重复数据。 为什么,因为从表面上看,这种黑客不再存在,但是将其从代码库中删除真的很困难,因为代码绝不是孤立的。 而且,从我收集到的信息来看,不再需要这种hack(我不知道它的引入原因,但是在禁用它的情况下测试不会失败,至少看起来像这样,因为我没有进行深入研究) 。 您不应该认为这是针对猕猴桃的怨言,因为事实并非如此。 Kiwi令人敬畏,它的开发人员和维护人员构建了我多年来使用的工具,并且在编写ObjC代码时仍在使用。 阅读完代码后,我决定不想自己碰到此类问题,因此我添加了一条准则,使所有特定于宏的代码隔离。 如果我们将该准则应用于我专门为您编写的错误代码: 这不是唯一迅速解决的具体问题。 它们有很多,甚至没有用#标记。 因此,对于此类代码,更好的措施是至少将其隔离为单独的功能。 但是,这也不是最好的主意。 为什么? 我们在整个代码中具有不同的特定操作,这导致我们遇到#if os(iOS)的相同问题,该问题既重复又难以重构。 因此,更好的方法是使用与注入闭包和隔离此类代码相同的方式进行操作: 您可以在以前的演讲中读到更多有关注射的信息: 没人管的常见错误– Swift扩展 最糟糕的编码方式。 […]
在创建界面时,Swift社区一直在使用情节提要和程序化进行激烈辩论。 看起来苹果一直在推动社区使用故事板,并将其用作未来的标准。 但是,使用情节提要仍存在一些缺点。 我想简要讨论使用每种方法的优点,并谈谈我使用每种方法的个人经历。 故事板 1.易于使用 刚开始学习iOS开发时,我被教使用情节提要。 我认为这很简单而且容易学习。 经过一两天的学习故事板,它只需快速点击即可。 如果我需要使用按钮,标签,文本字段或segue创建一个新的视图控制器,则很容易实现。 只需单击几下并拖放,即可为应用程序创建一个简单的布局。 与以编程方式进行比较相比,仅创建布局可能会成为一个漫长的过程。 这是程序约束的示例: 让sampleView = UIView() view.addSubview(sampleView) sampleView.translatesAutoresizingMaskIntoConstraints = false sampleView.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor).active = true sampleView.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor).active = true sampleView.widthAnchor.constraintEqualToAnchor(view.widthAnchor).active = true sampleView.heightAnchor.constraintEqualToAnchor(view.heightAnchor).active = true 您可以看到仅创建一个简单视图就需要很多代码。 现在,假设对所有按钮,标签,文本字段等执行此操作,可能会变得很乏味。 重要的是要包含translatesAutoresizingMaskIntoConstraints和.active = true ,否则我们的视图将不会显示。 很多时候,我会忘记包括这两行代码,并且想知道为什么我的视图不会显示。 2.视觉 使用情节提要的主要优点之一是,它可以为您的应用程序提供很好的视觉表示。 您知道每个按钮,标签,文本字段和视图的外观。 只需单击几下并进行调整,即可轻松创建整个视图。 此外,还会在视觉上呈现约束,对约束的任何调整都将以不同的颜色显示。 程式化 1.控制 对所有UI元素进行编码将给您一种控制感。 通过StoryBoard可以实现的任何事情,都可以通过代码来完成。 您确切知道可以为UI元素创建哪种设置。 例如,如果我决定将一种字体设为粗体,则必须单击我的所有UI元素并将其更改为粗体,您会发现您可能会很容易忘记进行更改。 在代码中更改设置很容易,因为您确切知道所有UI元素的放置位置。 2.可重用性 我知道我已经提到过,在代码中创建一个简单的视图可能是一个漫长而艰巨的过程,但是我们可以在整个项目中重用这些代码。 如果要在视图中创建标签,则可以复制大部分代码,并进行一些小的调整。 繁荣! […]
曾几何时,在一个并不遥远的王国中,有一个邪恶的女王。 她的名字叫NSObject。 为了好看,她正在给人们很多礼物。 但是她提供给他们的最大宝藏是代码重用。 这种代码重用是通过继承实现的。 多亏了这一点,女王才得以世代代代地控制着她所有的人民…… 邪恶的女王控制着她的王国几十年,一天来了……一位敏捷的巫师。 他的名字叫克里斯托瓦尔(Christobal),但在澳大利亚他以the大师闻名。 巫师想在女王的王国旁边创建一个新的王国。 为此,他带来了不同种类的人:类,结构和枚举。 当女王得知他的计划时,她向巫师发出了诅咒。 幸运的是,向导很强大,只有类被继承诅咒所感染。 两国之间的战争持续了好几年,直到有一天……巫师离开了! 因此,现在是我们继续战斗并做到这一点的责任,让我们看看制胜法宝。 在向导王国中,出于多种原因,您可能需要使用那些受感染的类。 也许您使用UIKit,或者您想要引用类型,或者只是想重用一些代码。 如果使用UIKit,那注定要失败。 在某些时候,您将必须从其中一个UIKit类继承,这意味着您将必须从Queen中继承! 但是您可以通过使用final关键字来停止诅咒的传播。 您可能需要一个类,因为您需要引用类型而不是值类型,因此您可以拥有可以从不同位置访问的内容。 在这种情况下,您不必继承女王。 但是,您仍然必须再次使用final关键字来停止诅咒的传播。 最后,您可能正在使用一个类,以便您放入其中的代码可以在其子类中重用。 如果这是您正在做的,就停在这里! 在代码重用方面,还有许多其他工具可供您使用。 而且在几乎每种情况下,那些工具都会比继承更好。 总结一下:总是将您的课程标记为最终课程,或者…不要使用课程。 一起,让我们继续战斗邪恶的女王,直到我们摆脱继承诅咒!