您如何在Swift中进行键值观察? 你是否可以? 而仅使用Objective-C的本地KVO机制呢? 接下来是对ReactiveCocoa无名英雄的财产观察英雄的简要介绍: 财产 (和MutableProperty)。 马特·汤普森(Matt Thompson)在2013年为NSHipster详尽地解释了KVO的来龙去脉。 总而言之,我们只能说它是一个凌乱的Objective-C API,它今天仍然可以在Swift中使用。 除了您不能没有的场合(NSProgress有人吗?),我建议您不要使用它。 它的复杂性使其易于出错。 但是您说,Swift不提供本地等效功能…… 我听到了您的声音,但假设您可以简单地执行以下操作,以侦听更改并作为响应重新加载表视图,以获取所有新项目: 覆盖func viewDidLoad(){ super.viewDidLoad() viewModel.drafts.signal.observeValues {[弱自我]草稿在 self?.tableView.reloadData() } } 符合ReactiveSwift属性 如果我忽略提及didSet和willSet属性观察器,那么我将忽略有关Swift的本机观察功能的重要提示 。 有了足够的样板代码,您绝对可以将类似于KVO的东西拼凑在一起。 例如,您可以使用didSet监听属性更改, 然后通过委托重新分配这些事件。 纯粹主义者将更喜欢这种方法,因为它不涉及任何魔术,也不需要第三方库。 但是,ReactiveSwift旨在通过称为Property的单个概念来封装所有这些复杂性。 很简单,因为在本质上,属性只是一个值框,可以将其更改通知其他人。 这是从ReactiveSwift的1.0版本中精简的协议: 公共协议PropertyProtocol:类,BindingSourceProtocol { 关联类型值 var值:值{get} var生产者:SignalProducer {获取} var signal:Signal {获取} } 生产者和信号属性是您订阅的实际可观察值。 为什么要区分? RxJS README有一个不错的摘要: 冷的可观察对象在订阅时开始运行,即,可观察序列仅在调用Subscribe时才开始将值推入观察者。 值也不会在订户之间共享。 这与诸如鼠标移动事件或股票行情记录器之类的热观测值不同,这些事件甚至在订阅被激活之前就已经产生了价值。” 当应用于ReactiveSwift时,冷观测值对应于信号生成器,而热观测值则由“常规”信号表示。 在属性的上下文中,可以归结为: 启动生产者将发出属性的初始值 ,以及所有后续更改; 观察信号将仅发出观察开始后更改的值 。 […]
直接从上一篇文章开始,我们现在将开始更深入地研究功能性内容。 这是我们最后一次到达的地方: 让stringToURL:(String)-> URL? = {URL(string:$ 0)} 让urlToData:(URL)->数据? = {试试? Data(contentsOf:$ 0)} 让dataToImage:(数据)-> UIImage? = {UIImage(data:$ 0)} 让stringToImage:(String?)-> UIImage? = { $ 0.flatMap(stringToURL).flatMap(urlToData).flatMap(dataToImage) } _ = stringToImage(“ https://placebear.com/200/300”) 在可重用性方面,这是对原始版本的巨大改进,但我们可以走得更远。 在每个调用中都会重复flatMap调用,因此我们可以将它们归为一组吗? 让stringToURL:(String)-> URL? = {URL(string:$ 0)} 让urlToData:(URL)->数据? = {试试? Data(contentsOf:$ 0)} 让dataToImage:(数据)-> NSImage? = {NSImage(data:$ 0)} func fMap (_ fnc:@转义(T)-> U?)->(T?)-> U? { 返回{$ 0.flatMap(fnc)} } […]
Objective-Swift [名词]:以Objective-C的约定和约束编写的Swift代码 在学习Swift的早期,我可能不知道或根本太害怕使用该语言的强大功能。 我以Objective-C的形式编写了Swift代码,导致不必要的可变性和多余的额外行。 以下是一些我最终不懂得好处的习惯。 出队细胞 客观快速 迅速 避免cell变量 没有可选的cell可以强制展开 行数少 命名空间常数 客观快速 扫一扫 改进了相关常量的可读性 富有表现力的枚举 物镜转换 迅速 没有重复的字符串; 字符串与枚举大小写相同 添加诸如OPTIONS类的另一种方法仅需要添加另一种情况 阵列运算 客观快速 迅速 没有创建其他变量 富有表现力的代码读起来就像一句话; “获取姓名并映射到其大写版本,并为每个姓名打印出来” 类型检查 客观快速 迅速 没有力量解开 结论 从Objective C背景学习Swift可能会导致称为Objective-Swift的代码。 Swift比Objective C具有许多优势,因此,恳请您发现利用这些语言的高级功能的方法。
最近,我有机会为客户构建了一个iOS 聊天机器人应用程序。 该客户是一家汽车制造商,希望以一种“友好和对话的方式来获取有关您的新车的信息并排除故障。”原因很简单:在当今时代,人们很少在手套箱中寻找那种笨重的汽车手册。找出仪表板上红色闪烁的灯是什么意思。 相反,他们去了谷歌,或者他们给认识汽车的朋友发了短信。 它更快,更简单。 那么,如果汽车配备了具有所有答案的应用程序怎么办? 一个应用程序,您可以直接问“我如何打开巡航控制系统?”之类的问题,它仅向您显示如何执行此操作,直接来自汽车制造商本身而不是外部来源。 不幸的是,我只参与了该应用程序的前端。 所以我对后端感到好奇……这个机器人谁在发送所有这些JSON好东西? 事实证明,在当今时代,我们有很多选择(一些开源甚至有些免费)来构建机器人和AI,这可能是一个非常简单的任务。 因此,让我们构建一个可以处理人类基本互动的聊天机器人。 在本教程中,我们将在前端使用Swift 3,在后端使用Node和Express,并在AI中使用Wit。 威特 首先,我们需要注册机智:https://wit.ai/ 机智需要使用Facebook或Github帐户进行注册。 登录后,Wit会自动为您设置一个应用程序MyFirstApp 。 您可以转到设置并将其名称更改为任意名称。 您还可以在此处更改默认时区和语言。 机智有一个“快速入门”教程,其中向您展示了如何创建“故事”,这基本上是与您的机器人进行对话的一个示例。 在他们的快速入门教程中,他们向您展示了如何创建一个可以使用node js客户端发出天气预报的机器人。 对于我们的机器人,让我们从更简单的内容开始。 点击“创建故事”,并将其命名为“你好”。 在“用户说…”字段中键入Hello 。 对于“意图”字段,输入“值” greeting 。 接下来,点击“自动发送”,然后输入您希望机器人响应的消息。 我们将机器人命名为Lucas ,因此我们将使用: Hi, my name is Lucas. What should I call you? Hi, my name is Lucas. What should I call you? 作为漫游器响应,因为我们希望Lucas 知道与之交互的用户的名称。 […]
我们不是只是建立实例获得自己的唯一ID吗? 那整数是对象吗? 和弦一样吗? 为什么这些具有相同的ID? 答案在于可变性。 变异性 字符串一旦声明就无法更改。 尝试一下: 字符串是不可变的 。 整数,浮点数和元组也是如此。 在Python中使用不可变类型时,解释器通过将多个变量分配给同一对象来节省空间和时间。 由于我们不能更改“ dog”,为什么当我们说a =“ dog”和b =“ dog”时将其复制两个? 只需将两个指针分配给同一只非常好的狗即可。 另一方面,列表可以更改,并且经常会非常频繁地更改。 因此,可变类型会获得单独的对象,而不变对象则不会。 您也可以使用“ ==”和“ is”操作进行验证。 检查a == b会告诉您两个对象是否具有相同的值,而a == b会告诉您两个对象是否具有完全相同的id。 看起来像这样: 好吧,让我们再次加深对此的理解: 我们不是只是说字符串是不可变的吗? 如果a和b都是不可变的字符串,如何将它们添加到c? 答案再次涉及效率。 注意那里的c的ID是如何变化的。 Python没有改变c。 它将c 重新分配到一个可以容纳我们想要的所有字符串的新位置。 此过程称为串联。 它也适用于整数。 在C语言中,我们可以讨论如何通过值 (给函数提供数据的副本)或通过引用 (给函数提供实际数据,然后可以更改)将数据类型传递给函数。 那么,用Python处理什么呢? 正如您所怀疑的,答案与变异性有很大关系。 如果您传递一个函数,例如一个int,它将传递该值。 这基本上意味着该函数将创建一个新实例,无论您赋予它什么值,然后使用它。 值不变,ID不变。 您可以猜测可变列表会发生什么。 正如标题中所承诺的那样,让我们结束一些有关整数的有趣事实。 当然,它们是一成不变的。 如果您说a = 1,b = […]
Swift结构实例的内存布局的基础知识。 Swift类型在内存中处理时要考虑三个属性:大小,步幅和对齐。 尺寸 让我们从两个简单的结构开始: struct Year { let year: Int } struct YearWithMonth { let year: Int let month: Int } 我的直觉告诉我, YearWithMonth的实例比YearWithMonth的实例更大(它占用更多的内存空间)。 但是我们是这里的科学家。 我们如何用硬数字验证直觉? 内存布局 我们可以使用MemoryLayout类型来检查一些有关类型在内存中的外观的属性。 要从结构的类型中查找结构的size ,请使用size属性以及通用参数: let size = MemoryLayout.size 如果您有该类型的实例,请使用size(ofValue:)静态函数: let instance = Year(year: 1984) let size = MemoryLayout.size(ofValue: instance) 在这两种情况下,大小均报告为8个字节。 毫不奇怪,我们的结构YearWithMonth的大小为16个字节。 回到尺寸 结构的大小似乎很直观-计算每个属性的大小之和。 对于这样的结构: struct Puppy { let age: Int […]
2天前,我已将申请提交给Apple的WWDC 2016学生奖学金。 似乎每年我真的很想这样做,但是今年我终于做到了。 即使我没有赢球,这也感觉像是巨大的成就。 自从在2014年WWDC上发布《 Swift编程语言》一书以来,我就一直在学习Swift,但是我一直在努力学习Cocoa框架,因为那里有很多东西需要学习。 最近,我在业余时间对Web项目进行工作变得有些无聊。 可能是因为我现在是按职业划分的Web开发人员,或者也许我只是对该平台感到厌倦。 但是,无论哪种方式,我都认为在学习iOS开发方面取得成功的最好方法是仅构建一个应用程序并填补我的空白。 这将我们带到名为Z Split的应用程序中。 Z分割 我从一月份开始这个项目,甚至在考虑可以将其提交奖学金之前。 这是WSplit,Llainfair和LiveSplit的计时器。 那里有很多分割计时器,但在iOS或OS X上没有真正的分割计时器。这是我想填补的空白。 我想制作一个优雅的分割计时器,并利用平台的本机API和特定功能。 我使用了Autolayout,Core Data,3D Touch,Watch Kit,UIKeyCommand等技术。 我和父亲一起设计了该应用程序。 我们决定为应用程序选择一个黑暗的主题。 我通常喜欢在应用中使用深色主题(其中一个是Tweetbot)。 轻量级版本肯定会在将来的某个时候问世。 iOS 10即将推出全系统黑暗模式! 3月,我参加了尝试! 东京的Swift会议。 那里有很多很棒的演讲者,我在那里学到了很多很棒的技巧。 其中之一:Swift中的协议/扩展确实很棒! 我在代码中使用了协议来简化两件事:自定义UITableViewCells上的渐变和简单的CoreData表。 他们使我节省了重复的代码并精简了我的View Controller,以使它们不会变得无所不包。 开发应用程序中最难的部分之一可能是让Core Data正常运行以使所有内容正常运行。 这是一个非常不错的框架,但是对于像我这样的新手来说,学习曲线相当高。 持久性系统需要管理很多棘手的“陷阱”。 例如,有一次我的应用需要花费几秒钟来加载每个视图,因为从核心数据存储加载拆分/路由图像会阻塞UI线程。 而且我什至还没有进入后台线程管理的更高级的功能。 开发Apple Watch扩展应用程序也很有趣。 我想让它尽可能简单,因为老实说,由于手表上第三方应用程序的加载时间,您实际上只能拿起手机。 当前,它只是用作运行状态的快速状态指示器,您可以通过强制触摸菜单执行诸如拆分,暂停等操作。 将来,我可能会考虑向手表应用程序添加更多独立功能。 但就目前而言,我认为它运行良好(只要您的手机在附近)。 这可能不是最好的活动指示器,因为它包括库提交(我使用了1个cocoapod,RSKImageCropper)和情节提要,这些情节提要增加/删除行。 但这给出了我随着时间的推移在该项目中活动的总体思路。 即使这个项目不是在宣布奖学金后才构思的,但过去的两周绝对是一次按时完成任务的大型补习班。 未来发展 我计划继续开发Z Split,并在未来几周内将其提交给App Store。 我想补充很多功能,在整个奖学金期间,我基本上只能达到最低要求的功能集。 我要添加的其他功能包括: […]
多线程和并发对于现代应用程序是必不可少的……但是,Grand Central Dispatch是用于管理并发操作的系统级库,它具有iOS SDK中较为麻烦且不友好的API之一。 不再。 Swift 3带来了对Grand Central Dispatch语法和用法的许多改进。 这是一些新功能的快速浏览。 dispatch_async 以前,我们将选择调度方法(同步与异步),然后选择要向其调度任务的队列。 更新后的GCD会颠倒顺序-我们首先选择队列,然后应用调度方法。 最常见的GCD模式之一是在全局后台队列上执行工作,并在工作完成后立即更新主队列上的UI。 新API的外观如下: 队列属性 您会注意到,队列现在在init上具有属性。 这是一个Swift OptionSet,可以包括队列选项,例如串行与并发,内存和活动管理选项以及服务质量(.default,.userInteractive,.userInitiated,.utility和.background)。 服务质量取代了iOS8中不推荐使用的旧优先级属性。 如果您习惯了优先级队列,请按照以下方法将它们映射到QOS案例: * DISPATCH_QUEUE_PRIORITY_HIGH:.userInitiated * DISPATCH_QUEUE_PRIORITY_DEFAULT:.default * DISPATCH_QUEUE_PRIORITY_LOW:.utility * DISPATCH_QUEUE_PRIORITY_BACKGROUND:.background 内存和活动管理选项是今年的Apple OS版本(OSX 10.12,iOS 10.0,tvOS 10.0,watchOS 3.0)的新增功能。 这些功能包括使用.initiallyInactive在非活动状态下启动队列或使用.autoreleaseInherit,.autoreleaseNever和.autoreleaseWorkItem为队列设置自定义自动释放设置的功能。 工作项目 队列不是GCD获得Swift OptionSet的唯一部分。 工作项目也有更新的Swift语法: 现在,工作项可以在初始化时声明质量或服务和/或标志。 这两个都是可选的,并且会影响工作项的执行。 这些标志是一个选项集,其中包括以下选项:barrier,detached,assignCurrentContext,noQoS,InheritanceQoS,forceforceQoS。 一次派遣 dispatch_once对于初始化代码和仅执行一次的其他功能非常有用。 在Swift 3中,不建议使用dispatch_once,而应将其替换为全局或静态变量和常量。 dispatch_time_t dispatch_time_t是将指定时间转换为可以提供给队列的UInt64的函数。 更新的GCD为此引入了更友好的语法(告别NSEC_PER_SEC)。 这是一个使用after之后的示例: .seconds是名为DispatchTimeInterval的新枚举的一部分。 这些案例具有一个代表计数的关联值。 目前支持: * […]
我们都学习了数据结构,并以C / C ++实现。 在这个故事中,我将迅速说明一些使用泛型的基本数据结构。 让我们从堆栈开始。 注意:这个故事只是一个想法,重点在于基础知识。 欢迎提出建议和改进。 什么是堆栈? 我们都知道这是对的! 仅供参考,这是一个简单的例子– 我将定义一个可以推送/弹出任何类型对象的Stack类。 为了方便起见,我假设这些对象将确认为CustomStringConvertible协议(以便我可以打印其描述) Stack :CustomStringConvertible 这是使用泛型对象T的简单类声明 在单个链接列表中,第一个节点将是开始/根节点,下一个节点将是nil 。 创建一个班级名称 类LinkList :CustomStringConvertible,其中T:可比较,T:CustomStringConvertible 问:为什么在这里要求可比 ? 答:在搜索特定节点的情况下,我需要比较元素。 因此,为了进行比较,链接列表中的元素应符合可比较协议。 如上所示,声明称为startNode的私有节点。 注意:在这里假设理想情况,您可以管理空/零情况 append:此函数将在列表末尾添加元素。 如果链接列表为空,那么将要添加的第一个元素将是起始节点。 insert:此函数将在链接列表的开头添加元素。 如果链接列表为空,那么将要添加的第一个元素将是起始节点。 插入(位置):这会将节点添加到给定位置。 removeFirst:此函数将从头开始删除节点。 removeLast:此函数将在最后删除节点。 remove(position):这将从给定位置移除节点。 搜索:它将根据数据搜索节点并返回其位置。 行使: 1.试用字母链接列表😝。 2.尝试制作双向/圆形链接列表😅 希望您能对如何快速使用泛型和实现基本数据结构有所了解。 我还添加了练习,希望您能进行探索。 如果听起来不错,请在Swift check中选择Binary Search Tree Swift中的二叉搜索树 从以前的帖子开始: medium.com 快乐编码😃!
欢迎使用本系列教程,这些教程将教您自动布局,从最基础的知识到您可能会发现的布局最复杂的任务。 尽管仅涉及使用NSLayoutConstraints编程工作, NSLayoutConstraints大多数内容都可以推断为使用Interface Builder。 十分简单 我们将使用EasyPeasy代替纯UIKit 。 有很多流行的Auto Layout库,它们提供了使AL更简单的语法糖,例如SnapKit , Cartography或PureLayout ,那么,为什么要使用EasyPeasy? 简单性:提供一种简洁但功能强大的领域特定语言。 类固醇上的自动布局:提供其他一些附加功能,例如冲突解决,有条件地应用约束,特征集支持,在不保留引用的情况下更新约束以及简洁的调试模式。 可靠性:也许由于其在近1年的使用寿命中100%的代码覆盖率,尽管安装了120个CocoaPods和190个存储库克隆(每周编号),但尚未报告任何实际错误。 但是,如果这还不够的话,那就是上述库的简短比较: