大家好, 前段时间,我们的设计师想要一个带有垂直滑块的批准页面。 此页面位于某些表单屏幕之后(用户在其中填写一些信息),并且通过向下滑动滑块可以看到其下面的页面。 同样,通过将滑块滑到底部,用户可以批准他填写的信息。 您可以在顶部看到一个丑陋的演示。 (完全由我设计designed) 对于此任务,我选择创建IBDesignable自定义滑块,该滑块使用xib文件通过情节提要板在其他项目中重复使用它。 我的主要目的是能够在故事板上看到我的自定义滑块。 我希望获得有关自定义视图的即时视觉反馈,而不是编译和运行项目。 通过使用IBDesignable您可以从情节IBDesignable中实时编辑通过xib创建的自定义视图,我想这真是太酷了。 在这篇文章中,我们有2章: 第1章:如何创建使用xib的自定义垂直滑块 第2章:如何制作 包含 IBInspectable 元素 的 IBDesignable 自定义视图 请注意,本文中将包含大量代码,我不想撰写单独的文章以保持完整性。 因此,您的职位很长。 希望您能找到对您有用的东西。 创建XIB 通过协议功能实现平移手势动作和与父视图的通讯 实现视图的实现方法 这些是我们要采取的步骤。 让我们开始使用滑块: 1.创建XIB 在此步骤中,我添加了一些屏幕截图,这些屏幕截图将对您有所帮助。 您也可以在Github上查看该项目以亲自查看。 您可以在文章末尾找到链接。 您可以在屏幕快照中查看视图层次结构及其IBOutlets 。 SliderPath:所有项目均发生的位置。 平移手势使用此视图获取坐标反馈。 thumbView:他认为您用手指滑动。 这也连接到手势识别器。 destinationView:隐藏视图以检查拇指是否已到达目标。 您可以在底部选择的第一个屏幕截图中看到此视图。 我选择在xib上添加平移手势,并连接其动作和插座,如相关屏幕截图所示。 2.执行平移手势 相关的IBOutlets和变量 var委托:KKVerticalSliderDelegate? @IBOutlet弱fileprivate var slidePath:UIView! @IBOutlet弱fileprivate var拇指:UIView! @IBOutlet弱的fileprivate var目标:UIView! @IBOutlet弱fileprivate var thumbTopConstraint:NSLayoutConstraint! @IBOutlet fileprivate […]
如果您不熟悉数据结构和算法,那么树数据结构就是一个很好的起点。 实际上,如果您曾经使用过JSON,那么您已经很熟悉这个概念。 树是一种数据结构,可用于对对象之间的层次关系进行建模。 该树由节点组成,每个节点具有以下组成: 一个值。 可选的父节点。 子节点列表。 术语 虽然树中的所有对象都被视为节点,但它们根据周围的上下文具有不同的命名约定。 根节点 :这是树的最高层的节点,并且是唯一没有任何父节点的节点。 叶子节点 :这是一个不包含任何子节点的节点。 Swift中的节点数据结构 这里要注意的一些事情是: 1. Node类对它拥有的值是通用的。 但这不是必需的,但是,它允许您以与数组相同的方式构建包含不同数据类型的各种树,从而有助于代码重用。 2.我们已将持有父节点的属性标记为弱。 由于父节点拥有对其所有子代的引用,而子代拥有对其父代的引用,因此我们将父代参考标记为弱,以防止创建强参考循环。 3.我们已将父级和子级属性标记为只读。 这是因为直接修改这些值可能容易出错。 最好通过Node类上的方法公开一个安全的API。 您可以看到,通过在Node上使用addChild方法,我们将永远不会忘记在新添加的节点上设置父级。 树木和递归就像面包和黄油。 您可以尝试: 1.创建一个在包含给定值的树中查找第一个节点的方法。 2.打印出节点及其所有子节点的文本表示形式。 在Swift算法俱乐部中更深入地了解这棵树的例子。
您是否曾经尝试过在项目中使用MVC,并且一直都在考虑故事板,NavigationController,Segue,ViewController和视图? 有时,您尝试将上述所有信息传递给模型,而您根本不想使用MVC。 但是幸运的是,SWIFT的功能足以为您解决这些问题。 故事板 我们必须在项目中声明的最重要的内容是Storyboard,这是您进行其余操作之前必不可少的。 我几乎在每个项目中都使用了SWIFT功能,但是您可以通过这些代码查找许多其他内容,也许您找到了您真正想要的东西。
UIScrollView是UIKit中一个古老且用途广泛的类,自iOS成为iPhone OS 2.0以来一直存在。 它提供了灵活性,可以呈现不适合设备屏幕的大内容。 iOS中最受欢迎的UIComponent(UITextView,UITableView和UICollectionView)是从UIScrollView类继承的。 →UIScrollView具有3个主要属性,分别为contentSize , contentOffset和contentInset 。 →内容大小: ScrollViews只需少量的设置和代码即可为开发人员提供强大的功能。 所有繁重的工作都由Apple处理,我们(Devs)得到了一个众所周知的委托(UIScrollViewDelegate)来管理其状态和功能。 ScrollView只是一个UIView对象,它具有动态原点并在其中移动内容。 它具有一个名为CGSize类型的重要属性contentSize ,它表示可滚动区域的大小。 滚动视图必须知道内容视图的大小 ,以便知道何时停止滚动。 其默认值为零,即使content-size小于滚动视图自身的大小 ,也必须将其设置为使用任何滚动视图。 在上图中,滚动视图的实际帧由黑色粗线表示,内容大小为男孩图像的大小。 →内容偏移量: 当用户滚动滚动视图时,用户可见的内容区域会更改。 内容视图在滚动视图中的位置称为内容偏移 ,并由contentOffset属性( CGPoint值)表示。 此属性由x和y值从可见区域的 原点 (左上角)到内容视图的 原点 (请看下图)之间的距离定义。 内容大小保持不变,但是内容偏移会更改以响应用户交互。 内容偏移量可以通过编程更改。 contentOffset属性是可读写的。 更有趣的是,您可以使用func setContentOffset(CGPoint, animated: Bool) animation func setContentOffset(CGPoint, animated: Bool)方法来设置内容偏移量的动画。 这将“移动”滚动视图,就像用户自己移动滚动视图一样。 →内容插入: 这是一个UIEdgeInset值,它代表滚动视图的内容应“填充”的区域。 将contentInset属性设置为UIEdgeInsetsMake(10,10,10,10)将在滚动视图的内容周围创建10点的空白。 边缘插入值也可以为负; 这将代表用户无法看到的滚动视图内容周围的区域(除非用户滚动到滚动视图的边缘之外)。 →UIScrollViewDelegate中有3组方法,它们分别响应拖动和滚动 , 缩放和滚动动画 。 滚动和拖动: func scrollViewDidScroll(UIScrollView) […]
现在在子菜单中打开“拦截”选项卡并启用拦截。 为什么? 通常,如果您只想听http请求,则不必这样做。 但是既然我想弄各种各样的东西。 我们必须以某种方式进行中间人入侵。 好。 我们现在准备好了。 下一步是准备我们的iPhone。 打开您的wifi设置并添加HTTP PRoxy。 这必须是您在Burp中设置的监听器IP和端口。 让我们做最后一步,向iPhone添加证书。 您可以按照portswigger网站上提供的说明进行操作: 在…中安装Burp的CA证书 在计算机上运行Burp的情况下,在iOS设备浏览器中访问http:// burp,然后单击“ CA证书”链接… support.portswigger.net 现在,让我们玩得开心。 我试图检查谷歌地图,以查看所有的流量。 因此,下次您设计REST api时,请考虑一下,也许有人可以从中获取信息。
在今天的文章中,我们将讨论一个非常常见的问题,我们iOS开发人员有时必须在我们的开发工作流程中处理这个问题。 问题是如何存储应用程序生产API密钥,以存储我们使用的服务,开发,测试或生产服务器URL以及其他可能过于敏感而无法通过代码添加到我们的存储库中的数据。 以及如何分隔持续集成管道以使用不同的API密钥,访问密钥,服务API地址或任何敏感数据进行生产,测试或开发构建。 有任何方法可以解决该问题。 包括在这篇名为Xcode中的Secret变量和CI的惊人文章中描述的内容,以获取乐趣和收益 由出色的Flawless App团队所带来的灵感之一,实际上是这个项目的灵感之一。这个小项目叫做Swift Variable Injector 。 另外,当我进行研究时,有人问我相同的问题的另一个思路是这样做的。 我们将在下面显示的示例方法与[1]中描述的方法非常相似,该方法使用Sourcery和代码生成基于环境变量值创建快速文件,并将其插入到Continuous Integration流水线中的项目中。 现在,我们将演示一个示例,说明如何使用Swift变量注入器执行文字值替换,将环境变量值注入到Continuous Integration Pipeline中的Swift代码中。 所以…… 开始吧 首先,创建我们的项目,让我们定义用于处理环境变量和Continuous Integrations值的类。 注意 :这些Xcode环境变量参数在启动时而不是在编译时传递给Process(App)。 这意味着您将使用这些参数启动该过程,仅当使用Xcode运行该项目时,您才具有这些值。 通常仅对开发有用。 如果您希望能够在不使用Xcode的情况下启动已部署的版本,则可以将CI类从var模式替换为键值。 但是重要的是,在提交和推送它时,不要让它静态定义。 :)) CI.swift类声明在连续积分的变量注入器步骤中要替换的变量。 注意:重要的是文字值与格式$(ENV_VAR_NAME)匹配。 在持续集成方面,我们必须定义一个环境变量,并在每个工作流程(生产,测试等)中为其指定值。 我将使用Bitrise服务在此处演示步骤。 但是,大多数CI服务都提供了所需的所有功能。 在这里,我们基本上为每个工作流程定义环境变量。 因此,例如,如果我们有一个生产工作流程和一个Beta测试工作流程,则可以在两者上定义键,但要使用不同的值。 在为每个工作流程定义变量或秘密之后。 现在,我们可以在构建步骤之前添加变量注入步骤。 您可以通过两种方式执行此操作: 使用shell脚本 您可以在构建之前定义一个步骤,以运行以下脚本来安装和运行变量注入器: #安装 CURRENT_DIR =“ $ PWD” cd / tmp curl -OL https://github.com/LucianoPAlmeida/variable-injector/releases/download/0.2.1/x86_64-apple-macosx.zip 解压缩x86_64-apple-macosx.zip cp -f ./x86_64-apple-macosx/release/variable-injector / […]
自苹果推出Swift以来已经两年了。 在最初的12个月中,我很犹豫地推荐Swift作为一种实现语言。 实际上,我认为我的确切话是“不”。 在Swift大一的时候,这些工具不稳定,语言和库还很不成熟。 但是,在过去的12个月中,语言在不断发展壮大。 苹果公司开源了Swift,并通过Swift.org向更广泛的社区开放了该语言的发展。 这鼓励了社区通过Swift Evolution流程对Swift做出的巨大贡献,而即将发布的Swift 3也从这些努力中取得了成果。 Swift 3带来了该语言在其短生命周期中所看到的最重大的变化。 Swift 3和“伟大的重命名” Swift 3带来的最重大更改可能是“ The Great Renaming”。 去年这一年,Swift Evolution Process提出了许多建议,以澄清和标准化Swift标准库的命名方案,以及Swift如何导入Apple现有的框架(如Foundation,UIKit和Core Graphics)。 这产生了“ Swift API设计指南”。 这个新的命名标准意味着在使用这些框架时,Swift 3将与Swift 2完全不同。 随着向Swift 3的迁移,几乎所有现有的Swift代码都将需要迁移到新的命名标准并遵循这些准则。 Xcode 8包含一个迁移工具来帮助完成此过渡。 工具很棒,但是就像大多数工具一样,它可以节省您的工作,而不是从过程中消除所有想法。 我认为,所有Swift应用程序代码仍将需要由人工迁移来审核和审查。 此外,迁移工具无法帮助您将现有的应用程序代码转换为新的API准则。 它仅解决您的代码如何与Apple框架交互以及该API的更改方式。 Swift 3和ABI稳定性 Swift 3的目标之一是ABI稳定性。 这没有发生。 这意味着为了将项目升级到Swift 3,该项目的所有Swift依赖项也都需要更新到Swift3。不可能将Swift 3应用程序与Swift 2库链接。 在接下来的12个月中的某个时候,Swift 3很有可能达到ABI的稳定性,而在今年的WWDC上,克里斯·拉特纳(Chris Lattner)表示,在考虑日后对语言的更改时,保持源代码兼容性将是一个强大的约束。 因此,希望明年不再需要“ Great Renaming 2”。 何时切换到Swift 3? 团队现在应该开始为此进行计划。 […]
作为像Perfect这样的免费开源软件项目,最大的挑战是如何在保持质量和凝聚力的同时,使社区参与。 作为项目“核心”团队的成员,我们经常离代码很近,看不到极端情况,也没有考虑到我们尚未遇到的情况-在这里使用库的人会遇到问题,错误,或优化机会对于项目的成熟至关重要。 幸运的是,git(在我们的特定情况下为GitHub)使用称为“请求”的流程使社区贡献变得容易。 “我很乐意为此做一个请求请求,但我不知道该怎么做” 在我们关于开放社区Slack组的日常讨论中,当被告知有关文档或代码更改的需求时,有人多次评论“我很乐意为此提出请求,但我不知道该怎么做”。 。 好吧,如果您曾经说过或曾经想过并且犹豫要为FOSS项目做出贡献,请继续阅读! 什么是“拉取请求” “拉取请求”这个术语有点奇怪,除了可能有“补丁”的概念外,它与git社区以外的任何事物都不能很好地等同。 实际上,拉取请求(也称为PR)是您提交代码更改同时促进公开对话和审阅的一种方法。 PR的简单解释是: 您可以修改自己的git存储库副本 一旦感到满意, 就会触发一个请求,将您的更改合并到原始存储库中,并说明您的操作以及原因 然后,项目管理员会查看您的更改并接受更改 ,或者就更改进行讨论。 实际中的拉取请求 为了逐步演示您作为读者的身份如何进行PR,我将描述对Perfect Documentation资源库进行PR的过程。 Perfect项目的整个文档集都是开源的,我们会定期更新主站点上的HTML版本-从GitHub存储库的Markdown文件生成。 这意味着,如果发现拼写错误或可以做出的改进,那么您将有能力提供帮助! 因此,我今天注意到CouchDB驱动程序文档中提到的版本不正确:它引用的majorVersion为0,应为1。 回到源代码的GitHub回购页面https://github.com/PerfectlySoft/PerfectDocs/blob/master/guide/CouchDB.md,我可以看到它也已经过时了,因此需要更改。 第一步,“分叉”存储库。 哇,更多git术语:“ fork”是在特定时间点故意创建的版本库。 想象一下,如果您沿着森林步道走,突然之间的路径被分成两部分,这就是“叉子”。 一个路径可能会继续到达预期的目的地,而另一条路径可能会将您带向完全不同的方向……有时会合并回到原始路径中。 “叉子”是在特定时间点故意创建的版本库的新版本。 要创建Perfect文档存储库的分支,请使用GitHub页面右上方的“ Fork”按钮。 然后,您会看到一个对话框,询问您要将新叉子放置在何处。 选择一个位置:您的列表可能比我的列表更短或更长时间…… 现在我们有了自己的fork,可以编辑文件了。 编辑并提交更改 对于我们将要进行的小更改,GitHub用户界面使操作变得简单。 对于更广泛的更改(尤其是涉及代码),建议将新的存储库克隆到本地环境,并在提交之前使用Xcode之类的IDE来编辑和测试代码。 看到此演示正在更改文档的一小部分,我将直接在GitHub UI中进行编辑。 在页面上以自己的仓库查看文件时,您会看到一个铅笔图标,用于进入编辑模式: 单击此按钮将使您进入编辑模式。 滚动到要更改的位置-在我的情况下,我想将“ 0”更新为“ 1”。 完成更改后,向下滚动至页面的“提交消息”部分,然后输入有关更改内容的简短说明: 现在,此更改仍在您的文档存储库副本(分叉)上,因此下一步是将路径重新组合在一起。 提交您的拉取请求 当查看分叉存储库的“根”(也显示自述文件的根)时,您将看到一个标有“新请求请求”的按钮。 单击此按钮将带您进入一个页面,该页面专门向您显示您的版本与父版本之间的所有差异。 它还会通知您是否存在任何妨碍成功的合并冲突。 单击绿色的大按钮“创建请求”,然后您可以借此机会总结在PR中所做的所有更改。 现在单击“创建请求请求”将在父资源库中向您显示可公开查看的PR条目。 请注意,有一个橙色的“ CLA助手”注释,以及一条消息“某些检查尚未完成”…… 该“ […]
正如我在“成为tvOS开发人员”中提到的那样,使用Apple TV时,其遥控器上缺少按键是最大的挑战之一。 对于非常常见的动作,有时很难找到直观的手势。 这些动作之一肯定是在频道之间切换的动作。 基本上没有办法使用数字键盘,P +或P-按钮进行调换,这在任何其他电视平台中都存在,而Apple Tv中则没有。 为AppleTv创建涂鸦 我很久以前与同事谈论Siri Remote的问题时,这是一个疯狂的主意。 拥有涂鸦手势识别器来代替传统的数字键盘不是很好吗? 类似于我们在Apple Watch中已经拥有的东西… 在接下来的几天里,我们进行了交谈之后,我做了一些尝试来创建这个概念的非常简单的原型,但每一个都失败了。 我发现的最大限制是,无论手势的实际初始位置如何,SDK报告的起始位置始终是数字化仪的中心,这意味着位置(x:960,y:540)。 随后的滑动将值作为与该起点的偏移量。 因此,实际上在Siri Remote中可能发生的情况是,手指完全位于同一点,您会从SDK获得不同的位置,因为它们取决于手指到达该点的顺序…🤕 第1集:路线 使用顺序说明是解决此问题的首次尝试,避免了SDK的先前限制。 由于手指的实际位置不可靠,随后的滑动从那里获取偏移值,因此很容易获得手势的方向顺序。 并根据这些指示来推断结果。 因此,如果用户以↗️➡️↘️⬇️↙️↙️➡️的顺序进行手势操作,我可以自动推断出2的结果,依此类推: 0:“⬅️↙️⬇️↘️➡️↗️↗️⬆️↖️⬅️” 1:“↗️⬇️” 2:“↗️➡️↘️⬇️↙️➡️➡️” 3:“↗️➡️↘️⬇️↙️➡️➡️↘️⬇️↙️” 4:“↙️➡️⬆️⬇️” 5:“⬅️⬇️➡️↘️⬇️↙️⬅️⬅️” 6:“⬅️↙️⬇️↘️➡️➡️↗️⬆️↖️⬅️” 7:“➡️↙️” 8:“⬅️↙️⬇️↘️➡️↘️⬇️↙️↙️⬅️↖️⬆️↗️➡️↗️↗️⬆️↖️↖️⬅️” 9:“⬅️↙️⬇️↘️➡️➡️↗️↗️⬆️↖️↖️↘️⬇️↙️↙️” 这是一个非常理论上的情况,基本上不会发生。 在现实世界中,总是存在错误和重复手势,这些错误和重复手势会生成疯狂的序列,与我们的任何理论模式都不匹配。 因此,我介绍了一些代码,以在获取方向序列之前清理一下手势……为了避免数字化仪的高精度导致错误的方向,将点移到与上一个位置过于接近的位置。 一旦确定了方向序列,就将Levenshtein距离应用于每个模式,结果得到最接近的匹配。 听起来是个不错的计划,对吧? 好吧,我不得不说实际上不是 我反复进行了很多工作,结果总是非常糟糕,特别是对于最长的手势(6、8或9)。 所以,我放弃了…… 第2集:CoreML 我已经把这个随意的想法放在失败的项目的抽屉里,然后继续我的生活,仿佛什么都没有发生😀 几个月后。 我当时在圣何塞参加WWDC 2017,甚至没有想到这个疯狂的主意。 那时Craig Federighi先生主持了会议,并提出了我实际上缺少创建涂鸦的工具……CoreML。 此时此刻,我立即再次谈到了涂鸦,并希望借助这项惊人的新技术再给它一次机会。 目前,我对机器学习的知识基本上为零,所以我一回到家就开始寻找更多信息。 我真的很惊讶,那里写满了关于机器学习的大量废话。 许多文档将其视为黑匣子,您在其中放入了一些数据,但没有对过程背后的数学进行任何解释,就得到了结果。 如果您此时也希望对机器学习有一个很好的介绍,建议您通过Google查看此youtube播放列表。 在短短的视频中,您会获得一个非常清晰的指南,适合没有魔术盒的初学者。 在我研究所有新世界的同时,Sri […]
在开发iOS应用时,无法逃避并发或线程问题。 在许多情况下,都非常需要线程,队列和并发的概念。 这些泛泛的概念确实非常广泛,但是对于苹果公司而言,在开发应用程序时,它本身就可以管理很多线程方面的事情。 首先让我们谈一下并发性—真正的意义是什么,为什么会如此重要。 确切地说, 并发是由CPU处理多个任务 ,仅此而已,没有什么大不容易理解的词:)。 早期的Apple设备安装了1个CPU,可以在多个任务之间进行上下文切换。 2011年晚些时候,iPad和iPhone升级为双核,是的,这是一个很大的举措。 苹果提供了可以用于执行简单任务的GCD(Grand Central Dispatch)和通常用于执行复杂任务的操作队列。 之所以需要并发专业知识的原因之一是保持UI响应能力,这可以通过以下示例来理解:在UITableView中需要滚动图像,而其下载和转换图像则需要时间并且有点慢,因此建议这样做在除主线程之外的其他线程上运行这些任务。 注意:默认情况下,所有UI更新任务都在主线程上执行。 如果我们在主线程上执行繁重或复杂的计算,那么它将导致您的应用程序的UI阻塞并使其无响应。 修改或更新相同资源的任务一定不能同时运行,我们需要确保资源是线程安全的。 术语“任务”和“过程”通常可以互换使用。 不幸的是,术语“多任务”通常用来表示一次管理多个进程的能力,而“多处理”是指具有多个处理器(CPU)的系统。 我们可以创建自己的线程,但是在没有专业知识的情况下使用此选项可能会导致很多问题。 在将任务分配给GCD或操作队列时,系统将自己管理线程。 我们可以创建多个任务并将其分配给队列。 每个任务分为多个单元,每个单元由可用线程执行。 系统将任务分解为多个单元并将其分配给线程。 在下面给出的图中,我们有一个包含6个任务的队列,该队列分为2个线程,“线程1”执行4个任务(紫色,黄色,红色和绿色),“线程2”执行2个任务(蓝色,橙色)。 在GDC和Operation队列之间进行选择取决于我们希望任务之间或与主线程进行通信的方式,因为两者都提供了使同步函数异步运行的各种方法。 一个人在处理并发时可能会面临3个主要潜在问题,而前两个可以通过使用GCD或Operation队列来解决: 比赛条件 优先级倒置 死锁 竞争条件:当两个线程尝试同时访问或更改同一资源时。 这完全取决于线程的调度方式以及它们的启动,睡眠和恢复时间。 Xcode 8具有Thread Sanitizer或TSan来找出潜在的竞争条件代码。 下图显示了通过两个线程访问资源的理想情况,其中线程在不同的时钟周期访问值以进行读/写。 但是有可能在线程2的写操作之前完成了线程2的初始化和读取操作,这在线程2的写语句之后给出了不一致的结果。 这可以通过下面给出的图表来理解。 竞争条件可以通过锁定将使另一个线程等待其完成工作的值来解决,也可以通过将串行任务一次限制在一个特定资源中来使用串行队列来解决。 优先级倒置: 当高优先级工作变得依赖于低优先级工作时,或者成为低优先级工作的结果时,就会发生优先级倒置 。 结果,可能会发生阻塞,旋转和轮询。 在同步工作的情况下,系统将尝试通过在反转期间提高较低优先级工作的QoS(服务质量)来自动解决优先级反转。 在以下情况下会发生这种情况: 当为串行队列上的块调用dispatch_sync()和dispatch_wait() 。 当互斥量由具有较低QoS的线程持有时,调用pthread_mutex_lock()时。 在这种情况下,将持有锁的线程提升到调用方的QoS。 但是,跨多个锁不会发生这种QoS提升。 在异步工作的情况下,系统将尝试解决串行队列上发生的优先级倒置。 让我们考虑一个示例,其中存在3个任务– task1,task2和task3,它们分别具有低,中和高优先级,它们需要一个公共资源。 首先, task1开始执行并锁定资源,而task2启动并暂停task1,但是由于它被task1锁定,它将无法访问公共资源,同时task3启动并暂停task2并开始执行,因为它具有较高的优先级,但是当它需要公用资源,因为它仍被task1锁定,因此它被阻塞。 在这种情况下,低优先级任务和中优先级任务被高优先级任务停止,而需要公共资源的高优先级任务被低优先级任务停止,这是优先级倒置的经典情况,如下所示: […]