我们从2016年4月开始我们的项目,并决定将其作为纯粹的快速代码库。 随着项目的发展,越来越多的快速文件被添加,我们开始注意到构建时间约为2-3分钟。 几个月后,我们得知该项目将花费大约7分钟的时间来构建 。 到处搜寻,我们发现了一些有趣的链接。 使用适用于Xcode 7.3.1的出色的Xcode分析器插件,我们试图摆脱项目中的头号罪魁祸首,并合并了一些拉取请求,从而将构建时间减少了3–6秒。 但是这些PR并没有真正影响整个构建时间。 仍然花了7分钟才能完成。 我们希望当Apple发布swift 3时,在构建时间上也会有所改进。 尽管编译器有所改进,但在构建项目时我们并未真正注意到任何改进。 更糟的是,当Xcode 8.0发布时,它曾经进行了完全重新编译,而不是进行增量构建,因此更改任何文件中的简单常量都将触发整个项目的重建。 (此问题稍后在Xcode 8.2中修复) 由于进行了这些重建,团队中的开发人员感到沮丧。 再次谷歌搜索,我们想到了Stack Overflow上的这个宝藏。 解决方法以加快构建速度 事实证明,将此简单标志添加到我们的项目设置中,可将编译时间从7分钟减少到1分钟。 只需在“项目设置”中转到目标的“构建设置”,然后单击搜索栏左侧的+按钮即可。 选择添加用户定义的设置 并将此文本粘贴到文本字段中 SWIFT_WHOLE_MODULE_OPTIMIZATION 并将相应的值设置为YES(对于调试版本)和“ NO(否)”。 启用“整体模块优化”后,Xcode会将所有swift文件编译为一个大文件,而不是单独编译每个文件。 通常,您会注意到据说可以对发布版本启用“整体模块优化”,这是因为如果编译器可以一次看到所有文件,则可以推断出优化并将其应用于您的代码库。 因此,请确保针对发行版配置将此设置为“否”,然后上传到appstore,以便获得swift编译器可以提供的编译时间优化。 作为附带说明,您可以参考此答案以了解在xcode中构建项目所花费的时间。 结论 容易忘记,Swift才2岁,许多贡献者仍在努力构建这种语言。 尽管构建时间一直是造成挫败感的很大原因,但是“整体模块优化”技巧为我们节省了很多麻烦,并允许我们继续编写越来越多的快速代码。 在Twitter上关注Practo Engineering进行定期更新。 如果您喜欢这篇文章,请给我们鼓掌。 这将帮助其他中级用户找到它。 我们也在寻找kickass开发人员。 如果您有兴趣,请访问这里。
关于2016年LLVM开发者会议的说明 2016年美国LLVM开发人员会议于11月3日至4日在圣何塞举行。 没有惊喜。 许多演讲者和与会者都来自Apple。 我很幸运有机会参加这次会议。 讲座涵盖了LLVM,Clang,JIT,编译器工具链和构建系统。 LLVM(以前称为低级虚拟机)是模块化和可重用的编译器以及工具链技术的集合,用于开发编译器字体的前端和后端。 它也是由Swift的创建者Chris Lattner在2003年创建的。当然,Swift使用的是LLVM。 因此,如果您对Swift感兴趣,那么您肯定想了解有关LLVM的更多信息。 构建软件的新架构 演讲者:Apple Inc.的Daniel Dunbar 由于某些原因,没有人喜欢CMake。 演讲中介绍了llbuild-一个新的构建系统。 它是围绕可重用,灵活和可扩展的通用构建引擎设计的,该引擎能够解决许多类似于“构建系统”的问题。 它支持C,C ++和Swift。 它是Swift开源项目的一部分。 当前,Xcode,Swift操场和Swift包管理器正在使用llbuild。 对于速度,忍者仍然比llbuild快。 但是,丹尼尔(Daniel)提到llbuild在将来可能与忍者一样快。 用CMake开发和发行Clang 演讲者:苹果公司的克里斯·比尼曼 LLVM用于使用autoconf构建系统。 演讲者分享了有关他们如何在LLVM 3.9中迁移到CMake系统的故事。 他给出了CMake的几个原因: 跨平台构建配置工具 简单而强大的脚本语言 在许多平台上支持本机开发和IDE 活跃的替代开源社区。 他还指出,一个好的构建系统是没人想考虑的。 有人确实向Chris Bieneman问了一个问题:“ llbuild vs. CMake,哪个更好?” Chris Bieneman没有给出答案。 我的理解是llbuild支持Swift,而CMake不支持。 处理寄存器层次结构 演讲者:苹果公司的Matthias Braun 演讲者谈到了编译器代码生成阶段的寄存器分配器。 这是非常有趣的话题。 LLVM的一大特色是LLVM IR使用了无限的单辅助寄存器机器指令集。 在代码生成阶段,寄存器分配器确定从LLVM寄存器到物理寄存器的映射。 这简化并改善了许多编译器优化的结果。 演讲者还展示了寄存器分配器中的最新算法,可将GPU着色器程序的平均寄存器计数减少20%。 也有一些关于Clang静态分析器,调试工具和编译器优化的讨论。 其中大多数处于研究阶段,不适用于大型软件项目。 您可以在https://llvmdevelopersmeetingbay2016.sched.org上查看完整的时间表。 […]
Kecelakaan kerja yang saya alami ini bukan rekayasa。 ar! sesaat setelah kejadian itu warna merah ada dimana-mana。 saya震惊! Mereka membanjiri xcode sebagai tanda错误。 Begini kronologinya。 Tiket dan的最后期限是tak kenal kompromi的datang silih berganti。 Akhirnya demi kecepatan开发,saya menggunakan SJProgressHUD untuk merender tampilan加载。 Dengan membabibuta,SJProgressHUD dipasang di banyak ViewController。 Prinsip pertama yang saya langgar: 不要重复你的自我 ! 塞莱赛项目。 Selanjutnya Tinggal维护Saja。 […]
编辑(2019年4月):原始文章写于2017年1月,回溯到Swift 3.0时代,当时Linux支持还很年轻。 截至此编辑之时,Swift已在5.0版本上发布,并且Linux支持比以前好得多。 如果您正在寻找有关Raspberry Pi上Swift的最新信息以及可以在系统上使用的预编译Swift二进制文件,我建议访问 Umberto Raimondi 博客。 一旦有更多时间,我将用新信息更新此帖子。 最近,我对编写与外部硬件设备(例如传感器或电动机)接口的软件感兴趣。 与外部硬件交互的最简单方法之一是通过Raspberry Pi。 小型计算机具有40个GPIO引脚,可让您将其连接到外部设备。 大约一个月前,我买了Raspberry Pi,看看我能用它做什么。 每天,我是一名iOS开发人员,为初创公司开发移动应用程序。 如今,我创建的大多数应用程序都是使用Swift编程语言编写的。 我爱斯威夫特。 新的Apple语言是现代,安全和富有表现力的。 尽管开发速度可能无法与Python等脚本语言相提并论,但是静态类型系统使整个应用程序更加安全可靠。 由于我精通Swift,因此我想探索它对Pi的支持。 这是我到目前为止发现的。 在Raspberry Pi上编写Swift需要两个主要组件: 该平台的Swift编译器和软件包管理器 一个支持GPIO的Swift库 尽管Apple确实发布了支持Linux的预编译Swift二进制文件,但它仅支持具有x86处理器的平台。 对Raspberry Pi等ARM设备没有官方支持。 但是Swift是开源的,在一些专门的贡献者的惊人工作下,Swift编译器被移植到ARM系统。 Umberto Raimondi最近发布了可在Pi上运行的Swift 3.0.2预编译二进制文件。 由于软件包管理器在那里被破坏,我在Raspbian版本上遇到了问题。 但是一旦我安装了Ubuntu Mate,然后安装了Swift Ubuntu二进制文件,一切都可以正常工作。 Umberto还是用Swift编写的GPIO库的作者。 您可以使用Swift Package Manager安装该库。 使用上述基础结构,我能够运行我的第一个Swift程序,以使用Raspberry Pi上的GPIO引脚点亮LED。 结论: Raspberry Pi对Swift的支持仍处于试验阶段,并由一组专门的开源贡献者推动。 地狱,甚至Linux支持都处于早期阶段,因为像Foundation这样的核心库尚未完全移植到OS。 没有IDE支持,起初,我使用nano编辑程序,这不是一种愉快的体验。 但是,Pi上的Swift可以使用,如果您想玩转,应该可以很快设置它。 希望苹果有一天会正式支持ARM平台,以便我们可以放心地部署Swift的全部功能!
依赖类型(有时称为约束类型)使代码更安全,更易于使用。 使用从属类型是最有用和鲜为人知的编程概念之一。 我希望阅读完这篇文章后,您会觉得自己像个机械师,刚刚学会了如何加工自己的零件。 我将提供一些背景知识,然后向您展示依赖类型如何拯救世界。 什么是从属类型? 在计算机科学和逻辑中, 从属类型是其定义取决于值的类型。 “整数对”是一种类型。 由于对值的依赖性,“第二对大于第一对的整数对”是从属类型。 —有关相关类型的维基百科文章 由于在Swift中基本类型和用户类型之间几乎没有区别,因此您很有可能已经使用了依赖类型。 考虑无符号整数类型: UInt UInt(正好:1)// 1 UInt(正好:1.0)// 1 UInt(正好:-1)//无 是否能够创建UInt取决于 a)您传递给初始化程序的值为正,并且 b)可解析为整数的值 使用UInt ,是在传达要处理的正整数的信息。 这是有帮助的。 是时候拯救世界了! 假设我们的工作是为核电厂编写软件。² 如果反应堆过热,则可能引发气候事件并导致地球生命的尽头。 我们需要一个函数来冷却它: func addCoolantToNuclearPowerPlant(加仑:整数) 可能您可以用负数来称呼它: func doEmergencyStuff(){ addCoolantToNuclearPowerPlant(加仑:-1000000) } 您已经排干了所有水,并引发了核灾难。 很容易看出为什么UInt类型将是此参数的更安全选择。 func addCoolantToNuclearPowerPlant(加仑:UInt) 现在,假设发电厂过热时至少需要一万加仑的冷却液。 在当前的定义中,我们不能偶然排放冷却剂,但是仍然可以将不足量的填料传递给冷却功能。 让我们通过在函数内添加检查来解决此问题,以免意外导致反应堆开销。 您会从检查中注意到,该参数的值存在隐式依赖性。 我们可以并且应该通过定义新的Dependent Type使隐式显式。 我们称它为Coolant 。 对Coolant此定义使用一个可失效的初始化程序来确保除非存在至少一万个Coolant否则它不会存在。 现在,我们可以重新定义冷却功能,如下所示。 现在,除了所需的最小Coolant剂量外,不可能用其他任何方法调用此功能。
Swift是在移动设备上很好地使用的一种语言,其中一些在(非常)有限的计算能力下运行—例如,以较旧的iPhone或Apple Watch为例。 在这种情况下,每个CPU周期都非常重要,精心设计的应用程序将充分利用它们。 减少应用程序占用空间的一种已知方法是通过缓存。 缓存通常被认为是一项棘手的业务。 当将诸如网页之类的外部资源放入缓存时,这是正确的,但是当我们仅考虑缓存纯函数的结果时,事情就容易得多。 如果某个函数始终为给定的输入返回相同的值,而不会产生任何副作用,则认为该函数是纯函数。 缓存纯非递归函数的结果 对于此类功能,功能编程是透明地提高其缓存效率的指定工具。 考虑以下代码: cached函数将一个函数作为参数,并返回一个新函数,该函数将计算与原始函数完全相同的结果。 但是,一旦第一次计算出一个值,它将被存储在缓存中。 因此,使用相同输入进行的任何后续调用将不再需要执行任何计算以得出正确的结果。 考虑到您正在编写2D游戏的代码,现在可以轻松使用标准三角函数的缓存有效版本: 如果您的游戏经常对相同的值进行三角函数计算,那么现在怀疑这种方法是否会对性能产生重大影响? 递归函数的问题 上面讨论的技术是如此易于使用,以至于人们可能认为它有一个陷阱! 确实有一个限制,或者说是一个限制。 当您使用非递归函数时,一切都很好,并且已cached函数就像一个符咒一样工作。 但是,如果您尝试将其传递给递归函数,例如: 您不会注意到性能的提高,并且实际上对于大于20的n值,该函数仍将花费大量时间返回-请记住,此函数在不缓存中间结果的情况下具有指数级的时间复杂度。 为什么会这样? 嗯, fib是一个递归函数,因此它在自己的体内进行调用。 确实,当您将fib放入cached函数中并调用生成的函数时,将进行缓存查找。 但是之后,对fib的递归调用仍将指向原始fib ,因此将不再发生缓存查找。 为了允许相同的缓存机制与递归函数一起使用,将需要其他工作。 编写高效的缓存递归函数 首先,我们将无法创建现有功能的缓存版本。 但是我们可以提供一个框架来轻松编写具有缓存效率的递归函数。 我们需要解决的关键问题是递归调用。 我们需要一种透明地将一些代码包装在递归调用周围的方法,以便在实际执行缓存查找之前执行它。 解决方案在于以下类型签名: ((In) -> Out, In) -> Out – In和Out是泛型类型。 此签名描述了一个带有两个参数的函数: 递归函数 递归函数的输入 通过这种类型,我们既可以使用第一个参数进行递归调用,又可以通过第二个参数访问函数的输入。 从那里,我们只需要编写一个内部函数,该函数实际上将在执行递归调用之前执行高速缓存查找。 尽管此实现确实有点复杂,但很棒的事情是使用非常容易,因为将其他语法保持在最低限度: 从那里,您现在可以使用缓存的功能,并看到它运行得更快! 从那里去哪里? 我上面描述的包含缓存中间结果的过程称为“记忆化”。 它的原理很简单:它将内存换为CPU周期。 尽管可以进行任何形式的折衷,但是它可以带来显着的计算加速,但这并不是万灵丹。 因此,在应用每个特定情况之前,必须考虑到每个特定情况: 在某些情况下,您可能需要限制高速缓存的大小,并实施某些高速缓存替换策略以管理高速缓存。 […]
当您了解基本知识后,在Swift中构建拍照应用程序将非常容易。 为了使用iOS设备的内置相机拍照,Apple提供了UIImagePickerController类。 从Apple开发人员库中: UIImagePickerController类管理可自定义的,系统提供的用户界面,以在支持的设备上拍摄照片和电影,以及选择在应用程序中使用的已保存图像和电影。 图像选择器控制器管理用户交互,并将这些交互的结果传递给委托对象。 在本教程中,我们将学习如何拍摄照片并将其显示在“图像视图”中。 步骤1 打开Xcode并创建一个新的Single View Application 。 确保输入Swift作为语言,并确保在设备中仅选择了iPhone。 第2步 转到情节提要,然后将“图像视图”从“对象库”拖到主视图。 转到“大小”检查器,然后输入以下值。 将一个按钮从“对象库”拖动到主视图,并将其放置在“图像视图”下方。 给按钮命名为“拍照”。 第三步 选择助手编辑器,并确保ViewController.swift已连接到ViewController。 Ctrl +拖动 从Image View到ViewController类,然后创建一个Outlet。 Ctrl +从Button 拖动到ViewController类,然后创建一个Action。 步骤4 转到ViewController.swift文件并创建以下属性: 然后,更改类声明行,以使ViewController符合UINavigationControllerDelegate和UIImagePickerControllerDelegate协议。 接下来,实现takePhoto IBAction方法。 图像选取器控制器使用Camera的源类型初始化,并且presentViewController方法以模态形式呈现视图控制器。 实现UIImagePickerController委托方法imagePickerController() 这用于关闭当前视图并将照片分配给“图像视图”。 第5步 生成并运行您的项目,并授予对iOS设备内置摄像头的访问权限。 选择“拍照”并拍照。 选择“使用照片”以在“图像视图”中显示您的照片。 超级简单! 我希望你能定时。 我认为17分钟很慷慨。
您是否曾经需要创建一个在每个已排列的子视图之间具有不同间距的StackView? 好吧,如果您有并且您的项目需要支持比iOS 11更旧的操作系统(您可以在iOS 11+中本地运行),则可能只是创建了一个空的子视图,并定义了宽度/高度并将其添加到其他子视图之间。 但是,嘿,有一个陷阱。 如果要隐藏原始排列的子视图之一(假设是中间的子视图),该怎么办? 隐藏它之后,很可能会有不希望有的间距,因为它的两侧都存在空的隔离子视图。 因此,您也必须隐藏一个空的隔离子视图,这可能是您要避免保持代码清洁的一种方法。 在本博文中,我将向您展示如何以更聪明的方式实现此方法,以便您的spacer视图自动随内容视图一起隐藏。 这个想法是添加一个连接到内容视图并与其隐藏的间隔器。 我们将通过在UIView(这将是我们的内容视图)上创建扩展来实现此目的,该扩展具有创建间隔视图并返回它的功能。 在函数内部,间隔视图将观察内容视图的“隐藏”属性,并对该属性的任何更改做出反应。 该功能将使用参数来区分垫片的尺寸,轴和优先级。 这是我们将要实现的功能的概要: 扩展UIView { func createSpacer(_ size:CGFloat,axis:UILayoutConstraintAxis,priority:Int)-> UIView { //这将是一个创建并返回间隔符的代码,该间隔符将观察self的“隐藏”属性(这是我们的内容视图) } } 然后,您将在ViewController中创建类似于以下内容的间隔符: 让aLabel = UILabel() yourStackView.addArrangedSubview(aLabel) yourStackView.addArrangedSubiew(aLabel.createSpacer(10,轴:.vertical,优先级:1000)) UIStackView间隔符:实现 我将向您展示依赖于ReactiveSwift的有效实现。 然后,我将描述我尝试过的其他方法以及为什么它们不起作用。 该实现还取决于SnapKit(这是自动布局框架),当然也取决于UIKit。 因此,请不要忘记将其导入文件顶部。 导入UIKit 导入SnapKit 导入ReactiveSwift 我认为实现非常简单。 在“ createSpacer”函数内,您将创建一个隔离器,即UIView。 然后,将其“ isHidden”属性设置为最初与内容视图的(isself)“ isHidden”属性匹配。 然后,您可以将内容视图的“ isHidden”属性的反应绑定到spacer的“ isHidden”属性,因此每次隐藏或取消隐藏内容视图时,都可以。 垫片也会自动隐藏或取消隐藏。 请注意,由于Objective-C的旧名称,signal:forKeyPath函数必须使用“隐藏”字符串作为参数。 之后,仅使用SnapKit框架创建所需的间隔物高度或宽度(取决于轴)大小约束,然后返回间隔物。 扩展UIView { 私有函数createSpacer(_大小:CGFloat,轴:UILayoutConstraintAxis,优先级:Int)-> UIView { […]
最近几个月,我一直在开发开源Swift应用程序。 我需要使用rest框架将图像以及发布数据上传到Django。 虽然,有一些使用AF网络的Objective-C解决方案,但是我找不到一个很好的Swift解决方案。 使用Alamofire和Django rest框架非常简单。 我将解释以下步骤。 出于解释目的。 我将创建一个Django Model和序列化器类。 餐厅模型 REST API的餐厅序列化器 我们将在urls.py中添加rest api端点,并在views.py中添加逻辑。 在您应用的urls.py中添加以下内容。 url(r’^ api / v1 / list / new / $’,views.RestaurantList.as_view()) 我们都站在Django一方。 现在,是时候编写一些快速代码了。 首先,创建一个Podfile并添加pod’Alamofire’,’〜> 4.3.0’。 安装Pod之后,让我们创建一个多部分表单上传请求。 我不会编写用于从照片库中选择图像的其他代码。 您可以参考主存储库。 为此,您应该将Alamofire的上载api与多种格式的数据一起使用,因为我们要上载图像以及发布数据参数。 Django rest框架将负责其余的工作! 始终在其他参数之前为图像/文件添加multipartFormData 如有任何疑问,请随时在评论部分提问! 对于本博客,我假设:Swift 3.0,Xcode 8,Python 3.5,Django 1.10,Django Rest framework 4.0和Alamofire 4.0版本
3:“我们都是WWDC前奖学金获得者。” 与工作流程的创造者 听剧集 通过RSS订阅 在iTunes中订阅 注意:此情节录制于2017年3月12日,之前Apple于2017年3月22日收购Workflow。 苹果收购工作流程 对于本集,我采访了iOS应用程序Workflow的创建者Nick Frey,Conrad Kramer和Ari Weinstein。 Workflow是iOS自动化应用程序,于2014年12月在App Store中首次亮相。AriWeinstein共同创立了Workflow。 他退出麻省理工学院,共同创立了该公司,以跟随他对开发出色软件和产品的热情。 康拉德·克莱默(Conrad Kramer)共同创立了Workflow,他将大部分时间都花在工程上。 6年前,他开始进行iOS开发,在加入全职工作流程之前,曾参与过多个副项目。 尼克·弗雷(Nick Frey)在爱荷华州长大,在爱荷华州立大学学习计算机科学仅一个学期,然后辍学与康拉德(Conrad)和阿里(Ari)共同创立了Workflow。 这是我在iPad和iPhone上最常用和最重要的应用程序。 我要感谢Ari,Conrad和Nick在忙碌的日程中抽出时间与我谈谈他们的编码起源故事和学习编码。 工作流程 工作流程网站 工作流程文件 Fraser Speirs:网站 弗雷泽·斯皮尔斯(Fraser Speirs):Twitter 意外技术播客 跳房子 Mac OSKen播客 帆布播客 洗了情绪播客 克里斯·拉特纳(Chris Lattner):网站 克里斯·拉特纳(Chris Lattner):Twitter 阿里·温斯坦(Ari Weinstein):Twitter尼克·弗雷(Nick Frey):Twitter Conrad Kramer:网站 康拉德·克莱默(Conrad Kramer):Twitter 工作流程总部 关注@_SwiftTeacher 关注@bfoutty