Tag: 编程

学习Swift背后的编译器基础架构

关于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上查看完整的时间表。 […]

依赖类型(在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中制作高效缓存功能

Swift是在移动设备上很好地使用的一种语言,其中一些在(非常)有限的计算能力下运行—例如,以较旧的iPhone或Apple Watch为例。 在这种情况下,每个CPU周期都非常重要,精心设计的应用程序将充分利用它们。 减少应用程序占用空间的一种已知方法是通过缓存。 缓存通常被认为是一项棘手的业务。 当将诸如网页之类的外部资源放入缓存时,这是正确的,但是当我们仅考虑缓存纯函数的结果时,事情就容易得多。 如果某个函数始终为给定的输入返回相同的值,而不会产生任何副作用,则认为该函数是纯函数。 缓存纯非递归函数的结果 对于此类功能,功能编程是透明地提高其缓存效率的指定工具。 考虑以下代码: cached函数将一个函数作为参数,并返回一个新函数,该函数将计算与原始函数完全相同的结果。 但是,一旦第一次计算出一个值,它将被存储在缓存中。 因此,使用相同输入进行的任何后续调用将不再需要执行任何计算以得出正确的结果。 考虑到您正在编写2D游戏的代码,现在可以轻松使用标准三角函数的缓存有效版本: 如果您的游戏经常对相同的值进行三角函数计算,那么现在怀疑这种方法是否会对性能产生重大影响? 递归函数的问题 上面讨论的技术是如此易于使用,以至于人们可能认为它有一个陷阱! 确实有一个限制,或者说是一个限制。 当您使用非递归函数时,一切都很好,并且已cached函数就像一个符咒一样工作。 但是,如果您尝试将其传递给递归函数,例如: 您不会注意到性能的提高,并且实际上对于大于20的n值,该函数仍将花费大量时间返回-请记住,此函数在不缓存中间结果的情况下具有指数级的时间复杂度。 为什么会这样? 嗯, fib是一个递归函数,因此它在自己的体内进行调用。 确实,当您将fib放入cached函数中并调用生成的函数时,将进行缓存查找。 但是之后,对fib的递归调用仍将指向原始fib ,因此将不再发生缓存查找。 为了允许相同的缓存机制与递归函数一起使用,将需要其他工作。 编写高效的缓存递归函数 首先,我们将无法创建现有功能的缓存版本。 但是我们可以提供一个框架来轻松编写具有缓存效率的递归函数。 我们需要解决的关键问题是递归调用。 我们需要一种透明地将一些代码包装在递归调用周围的方法,以便在实际执行缓存查找之前执行它。 解决方案在于以下类型签名: ((In) -> Out, In) -> Out – In和Out是泛型类型。 此签名描述了一个带有两个参数的函数: 递归函数 递归函数的输入 通过这种类型,我们既可以使用第一个参数进行递归调用,又可以通过第二个参数访问函数的输入。 从那里,我们只需要编写一个内部函数,该函数实际上将在执行递归调用之前执行高速缓存查找。 尽管此实现确实有点复杂,但很棒的事情是使用非常容易,因为将其他语法保持在最低限度: 从那里,您现在可以使用缓存的功能,并看到它运行得更快! 从那里去哪里? 我上面描述的包含缓存中间结果的过程称为“记忆化”。 它的原理很简单:它将内存换为CPU周期。 尽管可以进行任何形式的折衷,但是它可以带来显着的计算加速,但这并不是万灵丹。 因此,在应用每个特定情况之前,必须考虑到每个特定情况: 在某些情况下,您可能需要限制高速缓存的大小,并实施某些高速缓存替换策略以管理高速缓存。 […]

强大的参数

迅速解决问题 先前的代码存在一些问题。 首先,考虑到我们正在谈论的是REST API,我们知道我们碰到了相同的端点,因此我们在重复自己很多次。 其次,这看起来很像将Objective-C转换为Swift,最后。 我们知道我们可以做得更好。 解决方案 假设我们希望有一个“真相”点来通过网络层更新用户,我们可以定义如下内容: 通过此UpdateUserEndpoint ,我们现在可以将希望在服务器上执行的更改传递到其初始化程序中。 这解决了前面示例的所有问题,并且坦率地说,我认为它更具可读性。 这就是一个简单的示例,说明如何使用Swift解决旧的Objective-C“问题”。

星期五-第六周

好吧,我正式完成了一半。 太好了,但太吓人了。 我们完成了MakersBnB挑战,我对获得的成绩感到非常满意。 还有很多工作要做,但是我和我的小组已经决定在休息时间做更多的事情。 这是我们到的地方! 佩伦斯基/ VRADbnb 通过在GitHub上创建一个帐户为VRADbnb开发做出贡献。 github.com 我们的回溯速度为2.45; 还早,但是我们迟到了,那是我们教练唯一能做的。 他为我们提供了一些非常令人鼓舞的反馈,很高兴在大一周之后进行了很好的讨论。 我们做了更多的工作,但是今天的主要焦点是我们上面的同类的毕业。 他们都做了演讲,做得很好。 绝大多数小组都使用Makers以前从未学过的语言写过东西。 真是太神奇了。 我简直不敢相信今晚将是我们8周。 然后,我们吃了一些比萨饼和饮料,然后去了酒吧。 我的出门时间比平常要晚,但很高兴在家中观看Netflix。 我仍未决定我在休息期间将要做什么,但明天我将花一些时间看一下Swift。 我真的很喜欢在回来时完成我的第一个iOS应用的想法。 今晚我要从学习/学习/阻止中休息一下,因为我们要到一月份才能站起来! 我为我们已经完成了一半而长辈们已经完成而感到难过,但是我为他们和我自己为我走了多远而感到骄傲!

学习Swift和iOS开发第11部分:继承

在这篇文章中,您将了解继承。 不,不是那种有钱的亲戚过世而留下大量现金,然后辞掉工作而逃到巴厘岛度过永久假期的那种。 我们在谈论遗传,就像在遗传学中继承特征或特征一样。 稍后我们将详细讨论这一点,但让我们先深入研究代码。 创建家长班 首先,如果尚未打开Xcode,请点击Create New Playground 。 为其命名,例如Inheritance ,然后单击Next 。 选择某个位置以保存此.playground文件,然后单击“ Create以保存它。 您应该会看到类似下面的屏幕。 删除左侧的所有样板代码,但根据需要保留import UIKit 。 真正的继承是什么? 在iOS开发中,继承是面向对象编程的一项功能,您已在上一篇有关类的文章中了解了此功能。 类可以从其他类继承特征,这使其非常有用。 考虑到有关家庭的一切。 在每个家庭中,都有父母和孩子。 父母具有某些特质,这些特质会传给孩子们。 例如,我的头发是棕色的,而我父亲的头发是棕色的。 我从他那里得到了这种特质。 我们两个人之间还有许多其他相同的特征,但是我在许多方面与父亲有所不同。 虽然我中的许多人都很相似,但我拥有某些技能和特质,与我父亲不同。 在Swift中,我们将创建一个类作为父类。 它将包含许多一般特征。 然后,我们将创建一个子类,该子类将从父类继承特征。 子类将具有与父类相同的特征,但我们可以添加仅子类独有的特殊特征。 但是,让我们开始构建父类。 建立家长课堂 虽然我们可以创建有关实际父母的课程,并使之成为基于代码的遗传学实验,但我们将做一些更酷的事情-考虑超级棒的汽车! 🚗🚕🚙 撰写家长班 在您的Playground窗口中,添加以下Vehicle类,并为所有车辆具有的共同点创建一些变量: 车辆类别{ 变速轮= 4 var make:字符串? var模型:字符串? var currentSpeed:Double = 0 } 每辆汽车都有4个轮子,这就是我们创建该变量的原因。 但是,为什么我们没有为汽车的品牌或型号赋予价值呢? 嗯,每辆车都有某种制造商和模型,因此我们实际上不需要在父类中指定这些属性。 添加一些功能 在我们的Vehicle类中,我们实际上可以创建所有汽车都可以执行的一些功能: 车辆类别{ […]

ARC:Swift中的强引用和弱引用

我对撰写有关参考文献的博客的兴趣始于IBOutlets。 我一直想知道为什么IBOutlet很弱,或者这意味着什么。 弱? 我问自己,什么是弱变量? 考虑到这个问题,我继续阅读Apple的文档以了解其含义。 我几乎不知道,虚弱是一个比我想象的要复杂的话题的一部分。 我发现苹果使用自动引用计数(ARC)来管理和跟踪应用程序上的内存使用情况。 使用强,弱或无主等引用是使ARC知道何时为任何给定对象释放内存的方法。 在这篇文章中,我将重点放在强引用和弱引用上,因为无所有权将被保存以供以后的帖子使用。 让我们从强大开始 我们中的许多人甚至在没有意识到的情况下在代码中使用强引用。 实际上,每次我们声明一个类属性时,除非我们另外指定,否则它默认为强引用。 var name = String() 这是强参考周期的外观的直观表示: 本质上,强引用用于描述对象之间的关系。 当一个对象强烈引用另一个对象时,这将创建一个保留周期,以防止释放被引用的对象并将保留计数增加到1。换句话说,这些对象现在彼此保持活动状态。 在下面,我创建了两个类,一个类为Person类型,一个类型为Pet类型,它们具有强大的引用周期,以便我们可以大致了解代码中的内容。 类人{ 变量名称:字符串 var pet:宠物? 初始化(名称:字符串,宠物:宠物?){ self.name =名称 self.pet =宠物 } } 宠物类{ var所有者:个人? var pet:字串 init(所有者:人,宠物:字符串){ self.owner =所有者 self.pet =宠物 } } 在此示例中, Person通过其pet属性强烈引用了Pet , Pet通过其所有者所有权强烈引用了Person 。 此示例的问题在于,由于这些对象之间具有强引用,因此当不需要其中一个对象时,ARC无法释放内存。 从理论上讲,如果Pet在任何时候都不为零,那么Person仍然会强烈引用Pet,并且即使该类为nil,也无法释放该类的内存。 反过来,如果Person在任何时候都不为零,ARC也将无法为此对象释放任何内存。 为了防止此保留周期,我们可以创建保存弱引用的属性。 参考文献薄弱 弱引用是在声明之前使用关键字weak创建的。 弱变量名称:字符串? 与强引用不同,弱引用的保留计数为零,这是因为被引用的对象在某个点上可能保留缺失值,并且有可能被ARC释放。 […]

谈论我的泛型-第1部分(快速3)

“ 通用编程是一种计算机编程风格,其中,算法根据稍后要指定的类型编写,然后在需要以特定类型作为参数提供时将其实例化 。” — Wikipedia 使用泛型编写代码是一种编写函数和数据类型而无需指定需要使用哪种确切类型的方法。 顾名思义,泛型类型不是特定的。 通过使用泛型,我们可以编写非特定的代码,因此,我们可以以更清洁,错误更少的复杂方式抽象代码。 在第一部分的这篇文章中,我将讨论数组,字典和可选变量是泛型的示例。 第二部分将讨论编写通用数据类和结构,编写通用函数和约束通用类型。 第三部分将讨论“关联类型”和“通用where子句”。 泛型数组 数组是泛型类型的示例。 数组是容纳任何类型的事物的容器。 在Swift中,我们受益于类型推论,我们可以在不显式声明其类型的情况下创建数组。 由于我们不必指定任何数组的类型(因为可以推断出该数组的类型),因此该数组作为数据结构是通用的。 让月份= [“一月”,“二月”,“三月”] 上面,我有几个月的时间。 由于我给的数组类型参数是字符串,因此本月的实例被赋予了STRING的具体类型 。 换句话说,声明数组时应定义的类型。 数组的通用语法 尽管上述月份的数组未正式将类型声明为STRING,但是有一种通用的语法声明数组,如下所示: var springMonths:Array = [] 请注意,单词Array后跟尖括号中的类型。 我们可以在这些尖括号之间分配“通用类型”的名称。 对于泛型,规范是使用作为我们引用的任何泛型类型的占位符。 在数组上使用通用方法 数组是通用的,带有通用方法,例如.append() springMonths.append(“ March”) springMonths.append(“ April”) springMonths.append(“五月”) 您会在上面注意到,我在springMonths数组中附加了月份“ March”,“ April”和“ June”。 如果我接下来编写以下代码行,您会怎么办: springMonths.append(50) 如果您猜编译器会给我错误: 那你是对的! 由于我们声明了Array的类型为STRING,因此任何不是字符串的东西都会使编译器不满意。 泛型词典 字典也是泛型的,因为我不必直接指定每个键的类型或每个值的类型。 例如,在下面,我没有具体说明字典类型: let monthDaysDictionary = [“一月”:31,“二月”:28,“三月”,31,“四月”:30,“五月”:31,“六月”:30,“七月”:31,“八月”: 31,“ […]

学习Swift和iOS开发第9部分:数学运算符

数学是编程的必要部分。 没有解决的办法。 并非来自数学/科学背景的正在学习编程的人; 但是,那些没有工程学学位的人(提示:我也没有)仍然可以学习编码! 编程所需的数学通常不会超出大多数人所知道的范围。 在Swift中,可以使用几种运算符来执行数学方程式。 在这篇简短的文章中,我们将讨论每个。 配置 首先,如果尚未打开Xcode,请点击Create New Playground 。 给它起一个类似于Math Operators的名称,然后单击Next 。 选择某个位置以保存此.playground文件,然后单击“ Create以保存它。 您应该会看到类似下面的屏幕。 删除左侧的所有样板代码,但根据需要保留import UIKit 。 赋值运算符 就像在数学中使用等号一样,使用赋值运算符(=)来赋值。 在您的游乐场中键入以下示例,以了解其工作原理: 变数3 = 3 当我们创建上述变量并将其命名为three 。 我们将其设置为字面上等于数值3。变量的名称实际上是不相关的。 我们可以给它起任何名字,它仍然可以作为在整个代码中使用值3一种方式。 算术运算符 就像在数学课或图形计算器中一样,在Swift中使用了四个基本算术运算符(+,-,*和/)。 以下是一些示例,向您展示如何在Swift中使用它们。 将以下内容添加到您的游乐场: var product = 10 * 20 //乘法运算符为* var sum = 5 + 6 //加法运算符为+ var Difference = 10 – 3 […]

快速Swift技巧I

字典作为一线开关/盒 从技术上讲,您可以使用字典将switch case块重写为一行。 首先,创建一个字典,其中每个对都将大小写条件作为键,并将其对应的返回值作为值。 最后,由于字典在运行时可能有也可能没有键,因此我们使用nil合并运算符来处理默认情况。 例如,看看我们如何转换开关盒并返回带有其IndexPath的单元格高度: 自然,这种类型的重写将取决于您先前的逻辑有多复杂。 另外,请记住,并非总是单衬板是最佳选择。 您应该始终优先考虑代码的可读性。 但是,拥有另一种选择总是很好。 可变参数 可变参数是函数参数,其行为类似于常量数组,但在调用时以不同的方式表示。 代替使用数组符号,传递的元素用逗号分隔。 如果要使用这些参数构建自己的函数,只需声明参数的类型,后跟3个点。 例如,查看以下简单的UIView扩展以在单个调用中添加多个子视图: 在这里,我们可以根据需要传递尽可能多的参数。 但是,每个函数只能有一个可变参数。