Tag: swift

SOLID原则-第1部分

单一责任原则-SRP 因此,“四人帮”在20多年前为OOP设计模式奠定了第一个基础,尽管我认为这已经过时了,但在努力编写简洁的代码时仍然有用。 这个原则规定,一堂课只能做一份工作! 是的,这是单一责任的含义,无需加糖。 “一个类=执行一个操作”简单而愚蠢。 因此,假设我们有一个需要在服务器上 启用 / 禁用或打开 / 关闭 服务的要求,并且我们希望将此原理应用于核心。 我们可以从使用协议抽象表示开始,首先描述业务逻辑应该做什么,如下所示: 本系列文章使用Swift语言介绍了SOLID原理,并附有实际示例,下一部分继续: 第二部分OPEN / CLOSED原理 您还可以在github存储库上找到完整的游乐场 鲍勃·戈德温(@bobgodwinx)| 推特 Bob Godwin(@bobgodwinx)的最新推文。 移动团队首席工程师@dunnhumby Germany GmbH。 @Apple的粉丝… twitter.com

在Swift中使用值类型进行双向关联

双向关联。 实体之间的双向关系。 例如,一个总统和一个国家,一个导演和他的电影等。这种关系是一对一,一对多还是多对多并不重要。 使用值类型无法完全表示它们。 由于值类型语义的原因,总会有不一致的地方 。 我将使用简单的示例尝试解释原因。 一对一 让我们考虑一下由总统管理国家的情况。 循环不断地进行……每次进行更改时,都会复制值,终止所有可能的值,以形成一致的关系图。 最后的话 由于不可变性,不可能仅使用结构来表示2向关系。 有时有必要依靠引用类型,即类。 我给你引用《 Swift编程手册》的一句话: …。这意味着大多数自定义数据构造应该是类,而不是结构…Swift编程手册

自动引用计数(ARC)(速记3)

内存管理是开发应用程序时的关键因素。 如果程序使用大量内存,它可能会使您的设备停滞不前,从而使应用运行缓慢甚至崩溃。 幸运的是,作为一个快速的开发人员,您可以依靠自动引用计数(ARC)来使您的应用程序的内存使用降至最低。 这并不意味着您可以忘记应用程序中的内存,但是它确实可以为您处理大多数事情。 重要的是要注意,ARC仅在使用类时才起作用。 结构和枚举是值类型,因此与通过引用存储和传递的类相比,它们在内存中的存储方式有所不同。 他们以ARC方式工作 创建类的实例时,ARC会处理从内存中分配和删除实例的情况。 ARC知道通过跟踪对该实例的所有其他活动引用,可以从内存中删除该类的实例。 如果没有对该实例的活动引用,则引用计数为零,并且该实例从内存中删除。 例如-让我们创建一个具有名称的dog类,并在初始化和取消初始化时将其打印到控制台。 这样,我们可以跟踪ARC将实例添加到内存中的时间以及何时将其从内存中删除。 狗类{ 命名:字符串 init(name:String){ self.name =名称 print(“ \(名称)被初始化”) } deinit { print(“ \(名称)我们正在被初始化”) } } 为了演示的目的,我们将使用可选值,以便我们可以将它们设置为nil并查看是否调用了deinit。 让我们创建一个可选的Dog,然后在游乐场文件中将其值设置为nil。 在这种情况下,当我们使用名称“ Guts”创建Dog实例时,该实例对其有一个引用-变量guts。 当该变量设置为nil时,引用计数将变为零,并且名称为“ Guts”的Dog将被取消初始化。 让我们看一个示例,其中对同一实例有多个引用。 在此示例中,“ guts2”现在还引用了名为“ Guts”的Dog的实例。 请记住,“ guts2”未指向变量“ guts”,而是指向了guts指向的内存中相同的位置—这是名为Guts的Dog的实例。 现在,有两个变量引用内存中的同一实例,这意味着引用计数=2。Dog名称“ Guts”的实例未取消初始化,因为我们仅将其中一个引用设置为nil。 这意味着引用计数仍为1,我们还需要将“ guts2”设置为nil才能从内存中删除实例。 强弱 当我们谈论某个属性强弱时,它与ARC特别相关。 默认情况下,创建属性时,它将创建对指向其所指向的任何类的实例的强引用。 使用ARC,引用计数仅计算强引用。 因此,如果我们将一个属性标记为弱属性,它将不会增加引用计数,或者如果该实例是对该实例的唯一活动引用,则不会将该实例保留在内存中。 在此示例中,实例的引用计数仅为1,因为guts2现在是弱引用。 因此,我们只需要设置guts = nil即可使ARC取消初始化名为“ Guts”的Dog的实例。 从内存中删除了名为“ guts”的Dog实例后,guts2将不再能够引用它,而成为nil值。 […]

我讨厌我爱你:了解关闭和完成

封闭是Swift的一个很棒的小功能,我绝对讨厌。 它们提供了许多好处,当我第一次以正式形式遇到它们时,就被它们让一个类遍历另一个函数的范围来获取和设置我从未见过的变量的能力所震惊。 理论上闭包是如何工作的: 在我自己实施它们之后,我很快意识到它们确实是可怕的生物,使我的生活更加艰难。 闭包在实践中如何工作: 但是,很多……我的意思是大量的练习,阅读和询问一百万个问题,我很快就开始理解它们的工作方式以及何时以及如何使用它们。 之后,我觉得也许是我最初想到它们的方式引起了我的困惑,所以我想用做晚饭的比喻来简单地详细解释它们。 一个简单的关闭函数说明: 现在,当我们调用函数时,就是魔术发生了! 我们从函数makeDinner()上的紫色箭头开始。 当我们调用此函数时,我们需要为其提供两个参数,第一个是一个字符串(我们选择“牛排”),第二个是一个函数。 我们赋予原始功能(makeDinner)的功能是choiceSides。 当我们的makeDinner()实现在调用完成函数时达到其代码中的要点时,我们实际上停止了执行并开始运行传入的函数。 有一些方法可以运行makeDinner()的其余部分,而无需等待第二个完成,但是我没有在此处实现它以保持简单(好像)。 ChooseSides()函数的实质无所谓,只是知道它以字符串作为自己的参数,这是由makeDinner()提供的,当我们在类实例anthony上首次调用它时,我们直接将其提供给makeDinner()。 choiceSides()的结果是一个字符串,该字符串冒泡返回并进入makeDinner,并替换makeDinner()首次调用chooseSides()的位置(在我们打印的字符串的第二个插值处)。 如果这一切看起来都是令人费解的,我常常想知道我这样做时是否没有违反自然法则,但是直到现在仍然有效。 再往前走,我们可以直接从choiceSides()中提取代码,然后将其直接用作makeDinner()作为封闭函数,而不用传入choiceSides()作为参数。 查看上面代码的下半部分,看看原始方法和闭包函数方法都可以打印出相同的内容!

使用WebKit从Swift调用WKWebView JavaScript和从JavaScript调用Swift

许多移动应用程序都将远程网页合并为被动(静态)内容,或者在这种情况下作为UI的组成部分。 使用此处介绍的WebKit / WKWebView技术,您的本机应用程序可以更好地与Web内容集成,并为最终用户提供卓越的体验。 Swift和JavaScript之间的双向集成 在本文中,我们将构建一个完整的混合本机/ Web应用程序示例,该应用程序在本机iOS应用程序(用Swift编写)和移动网页(用HTML / JavaScript编写)之间使用双向函数调用。 通过利用这两个功能,我们可以构建一个高度健壮的混合应用程序,其中本机和Web组件作为平等的合作伙伴协作,以提供有价值的客户解决方案。 解决方案概述 最终的解决方案包含两个组件: 在Swift中开发的本机iOS应用程序 托管在远程Web服务器上的静态HTML / JavaScript网页(在本例中为Microsoft Azure托管)。 完成学习的应用程序实现了三个主要功能: #1-从远程加载网页。 如果您使用过WKWebView,那么您将了解所有有关此功能的信息。 加载UIViewController时,会将网页URL设置为WKWebView,该WebKView使用HTTP GET方法获取HTML内容。 #2 —从Swift操纵WebView的外观。 接下来,我们通过向WKWebView内容页面发送命令以根据本机Segment控件中的用户选择来更改页面背景颜色,来轻而易举地进入互操作性领域。 #3-从HTML / JavaScript回调到Swift。 最后,通过将本机iOS应用程序中的地理位置功能公开到网页,我们使解决方案更加复杂和有趣。 当用户输入地址时,在Web视图页面上按一个按钮,将完成以下操作: 网页(使用JavaScript)调用Swift函数,将用户输入的地址作为JSON对象传入。 Swift本机应用程序使用CLLocation异步调用Apple,以确定用户输入地址的纬度和经度。 从Apple返回纬度/经度时,Swift本机应用程序将调用网页中的JavaScript函数,以使用输入地址的纬度/经度来更新网页。 解决方案演示 在遍历代码之前,让我们演示完整的应用程序的外观(动画GIF)。 UI故事板设计 学习应用程序包含一个名为ViewController的 UIViewController。 ViewController在Storyboard中只有两个UI控件: 一个UISegmentedControl,允许用户将WebView背景颜色更改为五种颜色之一。 UIView,放置在情节提要中,用作WKWebView控件的容器视图。 更改网页颜色 为了深入研究混合解决方案,让我们实现一个从 Swift 到 WKWebView的简单调用。 ViewController具有与本机视图顶部的Segment控件中的颜色选择相对应的颜色成员数组。 让颜色= [“黑色”,“红色”,“蓝色”,“绿色”,“紫色”] 当用户在Segment控件中点击新的细分时,事件处理程序将调用JavaScript函数changeBackgroundColor ,并传递与用户选择相对应的字符串: @IBAction func colorChoiceChanged(_发送者:UISegmentedControl){ webView.evaluateJavaScript […]

迅捷:链式铸造

正如我之前在Swift的类型推断中所提到的。 我真的对在我的代码中各处编写iflet和guard感到厌倦。 Swift中的类型推断 我要坦白。 我真的对在我的代码中各处编写iflet和guard感到厌倦。 有… blog.idapgroup.com 为了概述问题,让我们假设有一个UITableView ,其中我们需要呈现来自不同继承层次结构的UITableViewCell子类: 然后,让我们想象一下,Swift开发团队会使iflet失效。 众所周知,xCode Swift迁移工具并非始终可用,在某些情况下,我们必须手动重写代码。 我在Swift选择器上进行了这样的转换,这对我来说是一个巨大的痛苦。 而且,在我看来,iflets违反了我们所有人都喜欢和崇拜的DRY原则。 非DRY代码在重构或重写方面确实很痛苦,因为您没有集中的访问点。 为了解决这些问题,我更喜欢使用自己的解决方案: 稍后我们将详细介绍实现细节,但是现在让我解释一下,为什么我(不是真的)认为这种解决方案更好: 它使用类型推断; 富有表现力; 它是可扩展的; 它很健壮。 是的,我知道,对于任何不了解它的新手来说,它会使学习曲线更加陡峭。 是的,开关模式匹配也可以做到这一点,尽管语法会更加冗长。 但是它最终提供的是,只要我遵守界面,就可以注入任何我想要的行为,无论Swift如何改变。 当然,如果您愿意使用它,那将最终由您决定。 我绝对喜欢,因为我可以用更少的按键来表达相同的逻辑,并专注于真正重要的东西(我关于我要表达的内容的想法,而不是我要表达的想法)。 那么,它是如何在后台运行的呢? 请阅读我以前有关强制转换功能的文章之一。 为了更大的利益,我将在此处概述其签名,但是您需要知道如何使用它: 我提出的解决方案的实质是基于Castable泛型类型的: 首先,让我们回答一个最明显的问题:“为什么我们要在一种情况下使用switch ? 原因是很简单。 为了让Swift在没有默认返回值的情况下处理这样的表达式,该函数应该是穷举的,除了涵盖所有枚举情况的开关,Swift都认为该函数不是穷举的。 穷举是指处理所有枚举的情况。 此外, 如果case的语法更差: 这将失败,并在预期返回’NonExhaustive ‘的函数中缺少返回错误,并使用默认返回值作为self重写它可以解决问题: 但这只是为了自己的利益而编写的太多代码。 可能会出现的第二个问题是:“它是如何工作的?” 您看,我认为Castable作为一种类型可以通过两种方式进行处理:匹配和提取。 通过匹配,我的意思是强制转换一个包装的值,如果强制转换成功,则使用强制转换的结果调用该函数。 为了能够链接操作,我只返回了另一个包装相同值的Castable 。 提取只是解包并返回一个值。 从我的观点来看,通过一遍又一遍地重写相同的行来创建Castable不是一个好主意。 试想一下,每次要使用匹配和提取时,都必须编写Castable.value(x).match(…这是最常见的用例,对吗?可悲的是,我们不能只创建一个全局变量函数超出Castable.value初始值设定项,因为Swift不允许泛型使用该函数: let castableFunction = Castable.value导致错误:无法推断出泛型参数“ Wrapped”注意:显式指定泛型参数来解决此问题 。我能说什么Swiftc,你喝醉了,回家。 因此,为了修复该问题,我创建了几个最常用的功能-我认为是这样的情况: […]

动画制作NSLayoutAnchor约束和所涉及的陷阱

正确布置iPhone应用程序有时会感觉像一个项目的20%占用您80%的时间/时间。 这就是为什么当苹果在iOS 9中用NSLayoutAnchor击中我们时,我抓住了让生活更轻松的机会。 如果您还没有花时间使用NSLayoutAnchor,请快速阅读一下NSLayoutAnchor入门,然后再回来。 今天,我想向您展示如何动画化我遇到的那些限制和最佳实践。 动画NSLayoutAnchor约束 如果您想在这里看到完整的项目,可以在GitHub上看到。 让我知道您在设置约束动画时所做的任何改进。 如果您已经阅读了本文,则非常感谢! 我真的希望这值得一读,并且您会分享/喜欢/心动,并让其他人知道这也值得他们度过! 请给我评论,我很乐意与喜欢这篇文章的任何人交谈! Auf wiedersehen! 有关

使用Core ML和Vision Framework进行图像识别

Core ML为开发人员提供了许多构建诸如图像识别,自然语言处理(NLP),文本预测等功能的可能性。 现在您将想到,很难在应用程序中实现这种类型的AI,但是令您惊讶的是,Core ML非常易于使用。 在本教程中,我们将看到只需几行代码即可将Core ML集成到我们的应用程序中。 那不是很酷吧? 让我们开始吧。 应用概述 我们正在尝试制作的应用程序非常简单。 我们的应用程序将允许用户从相机拍摄照片或从其照片库中选择照片。 然后,机器学习算法将尝试预测图片中的对象。 结果可能不准确,但是您将了解如何在应用程序中应用Core ML。 让我们开始吧。 建立专案 首先,使用Xcode 9创建一个新项目,然后选择单视图应用程序模板,并确保将语言设置为Swift。 创建用户界面 让我们首先移至Main.storyboard文件并添加一些UI元素。 在视图中添加UIImageView,UILabel和UIButton。 默认情况下,我向UIImageView添加了一个默认图像,此后有一个UILabel将显示其可信度的预测答案。 最后,有一个UIButton将帮助我们从“相机”或“照片库”中拾取图像。 让我们继续前进。 移至ViewController.swift文件并在UIKit import语句正下方导入Core ML和Vision。 在这里,您可以看到准确性没有达到目标,但是我们仍然可以清楚地知道如何使用Core ML模型。 您可以通过以下链接了解更多信息: 核心ML | Apple开发人员文档 Core ML针对设备上的性能进行了优化,从而最大程度地减少了内存占用和功耗。 正在运行… developer.apple.com 机器学习-Apple开发人员 充分利用Core ML这一在苹果产品(包括Siri)中使用的新的基础机器学习框架。developer.apple.com

Mengenal代表团pada Swift

彭加塔尔 Biasanya kalau bermain dengan UITableView ataupun UICollectionView杨diletakkan pada UIViewController Pasti akan menemui suatu语法sepiti ini … self.tableView.delegate =自我 Untuk bisa berinteraksi dengan tableView塔迪,misalkan melakukan suatu aksi tertentu ketika salah satu baris pada tableView telah dipilih maupun akan dihapuskan,maka kita sering kali menggunakan 代表团 pada tableView supaya bisa melakukan aksi dissebutbut。 彭巴哈桑 塞卡拉·巴哈萨(Secara bahasa), 代表团成员 auau […]

大中央派遣(GCD)

GCD是用于管理任务执行的库,对于开发人员而言,异步编程使开发更容易,更安全。 异步允许任务同时执行,而不是通过在不同线程/进程上并行运行来阻止当前执行线程。 通过在后台线程上处理长时间运行的块,同时仍允许用户与主线程上的UI进行交互,它使应用程序具有更高的响应速度。 术语 串行和同步是同义词,并发和异步是可互换使用的。 主队列-处理应用程序的所有UI和未明确要求在后台队列中运行的代码的队列。 串行-串行队列中的任务一个接一个执行,一次仅执行一个任务。 任务按照插入队列的顺序执行。 并发-允许您并行执行多个任务。 任务以它们添加到队列的顺序开始,但不必等待彼此开始执行。 执行和完成的顺序不是预定的。 dispatch_queues 有两种类型的调度队列(队列由dispatch_queue_t表示),串行的和并发的。 要使用串行队列,请使用主队列 让mainQueue = dispatch_get_main_queue 或创建自己的 让serialQueue = dispatch_queue_create(“ @ anthonyprograms”,DISPATCH_QUEUE_SERIAL) 使用并发队列时,有多种选择:使用系统队列或创建自己的队列。 有四个优先级不同的系统队列,从最高到最低分别是: DISPATCH_QUEUE_PRIORITY_HIGH DISPATCH_QUEUE_PRIORITY_DEFAULT DISPATCH_QUEUE_PRIORITY_LOW DISPATCH_QUEUE_PRIORITY_BACKGROUND 优先级指出哪个任务将首先运行,优先级越高,它执行得越早。 让systemConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0) 您可以创建自己的 让currentparallelQueue = dispatch_queue_create(“队列”,DISPATCH_QUEUE_CONCURRENT) 将任务提交到队列 将任务提交到队列时,它可以同时运行或串行运行。 运行dispatch_sync(queue)依次运行该块,该块等待该块完成,然后再继续执行下一个任务。 并且dispatch_async始终是异步的。 只是您将所有UI块排队到同一队列中,因此不同的块将按顺序运行,但与数据处理代码并行运行。 队列示例 输出:“ polo \ n marco”。 这是因为GCD正在将异步代码块添加到队列中并继续运行该代码。 但是,当您更新UI时会发生什么? 在处理UI的后台线程上运行代码将导致崩溃。 为了在后台执行某些块,然后使用该结果来更改UI,必须首先获取主队列。 团体 假设您有一些更复杂的事情,需要更多类型的处理,并且只想在所有任务完成后更新UI。 这样,您可以使用dispatch_group_t。 […]