Tag: 编程

Swift中的LC-3 VM

我遵循了“编写您自己的虚拟机”教程来编写VM。 我决定用Swift编写它,因为我已经有一段时间没有写Swift了,并且错过了编写Swift程序的机会。 码 可以在此处查看该项目的完整源代码。 在几年前阅读Nand2Tetris书和课程之前,我只写过一个VM,也曾是一个玩具,因此早就忘记了一些细节,这就是为什么这次练习是一个很好的复习。 您会注意到代码没有经过优化,但是可以正常工作,到目前为止已经足够了。 存储器和寄存器均表示为UInt16数组。 我本可以直接在内存中使用指向UInt16值的指针,这可能会更快,更优雅。 这是我在实施此项目时(重新)学习的一些有趣的事情。 标志延伸 LC-3 VM使用无符号的16位整数。 但是,某些指令(例如下面描述的ST(存储)指令)要求对一个无符号的16位整数与另一个少于16位的整数进行算术运算。 ST操作通过将寄存器SR指定的内容存储在通过将程序计数器偏移量(PCOffset)位0到8加到程序计数器(PC)的当前值而指定的存储位置中来进行。 PC与LC8机器中的所有其他寄存器一样,都是16位值,而PCOffset是9位宽。 为了能够通过两个值的加法运算,必须对PCOffset值进行符号扩展。 如果PCOffset的最高有效位为0,我们只需在PCOffset的左侧填充0,直到其长16位。 如果MSB为1,则PCOffset用1填充。 值的符号扩展基本上增加了二进制数的位数,同时保留了其符号(正/负)。 Swift中的溢出添加 与在C语言中在Swift中添加两个UInt16整数(或任何无符号整数)不同,C语言没有自动溢出处理功能。 例如,以下代码将在Swift中给出EXC_BAD_INSTRUCTION错误: let n: UInt16 = UInt16(UINT16_MAX) print(n + 5) //EXC_BAD_INSTRUCTION 为了选择无符号整数的溢出行为,必须使用溢出加法(或减法或乘法)运算符&+ 。 let n: UInt16 = UInt16(UINT16_MAX) print(n &+ 5) //4 终端模式 终端对stdin的默认行为是对键盘输入进行缓冲和预处理,直到遇到新行\n ,然后才将其传递给正在运行的程序。 此模式称为熟模式或规范模式。 要为VM实现checkKeyBoard()函数,我需要将每个单独的按键传递给我的程序,而无需任何缓冲并等待输入新的换行符。 这要求将终端设置为原始或非规范模式。 我们可以通过使用tcgetattr()读取终端的属性并将其修改为一个结构,然后将该修改后的结构传递到tcsetattr()来设置终端的属性。 到大端 编写此VM可以使您对字节序进行重新整理。 它提醒我,字节序是指整数字的各个字节的顺序(虽然字节序可以指的是单个位,但在实践中极为罕见)。 LC-3 VM程序是大端的。 大多数现代CPU体系结构都使用低位字节序。 […]

Codables神级

思雅有简单的入门文章。 Swift 4的即时通讯协议,您的电位器和补充剂应运而生。 洛斯·科德ables的潜在挑战 协议实施细则中的可变版本。 编码科摩皮 Hasta ahora的出血与los codables一样使用para mapear JSON。 JSON协议和JSON协议之间的对应关系。 En cae vamos a ansignar nuestros propios tipos como side un Int o un String se tratara。 日期和日期的使用日期。更改日期。 设置时间戳记,然后在DateModel上添加时间戳。 JSON: { “ name”:“ Pepe”, “日期”:1541423186 } 类型: 最终决赛: 可编码和易腐烂的底漆,油菜和玉米。 普通法院法典 让值=尝试解码器.singleValueContainer() Lo que estamos haciendoahíes sacar un contenedor de unúnicovalor,lo que quiere decir […]

开始Swift编程第1部分-变量,常量和类型

我知道那里有很多教程,Apple有很多学习Swift的资源,包括他们的WWDC视频(即使较旧的视频仍然有用,所以不要害怕几年前的视频)。 保罗·哈德森(Paul Hudson)的系列文章“用Swift入侵”非常适合概念学习,而他的系列文章就是我的入门方式。 Ray Wenderlich也提供了一些非常深入的教程,但是大多数教程都要求您在到达API之前就具有一定的知识。 我依靠Ray Wenderlich一次过。 最后,我找到了Cocoacasts,以获取有关核心数据的信息。 我想每两天在这个系列中创建一个新的部分。 根据主题所涉及的内容,可能需要更多时间来编写。 本教程与众不同 许多教程向您展示了如何做某事,几乎没有解释为什么您以某种方式做某事。 我的目标是教您如何尽我所能,以及增加社区反馈。 许多教程一次将所有内容都扔给您,我计划详细介绍该主题。 您会慢慢学习,但是到完成每个部分时,我希望我能够比在其他地方阅读相同内容所能教给您的更多。 本教程是什么 本教程的设计方式是,您将学习Swift编程的基础知识。 我将教的很多东西都可以转移到其他语言,但是所有语法都是用Swift编写的,使用相同语法的里程可能会有所不同。 虽然本教程并非旨在教您如何制作您的第一个应用程序(请参见下文),但它会教您一次又一次地用于制作第一个应用程序的基本构建基块。 本教程不是什么 本教程不会教您如何使用Xcode或如何制作第一个移动应用程序。 我不会讲授如何构建用户界面,使用自动布局,如何使用“在此处插入框架”或iOS中使用的各种文件类型。 也许将来,我会写一些系列文章,深入探讨其他主题,但是目前,我的唯一目标是教授语言以及事物与语言的关系。 系列目标 整个系列的目的不是要推出另一个几乎一无所知的程序员,而是要教新的程序员真正的编程。 从课堂和实践的角度,使读者对程序设计有一个更好的理解。 使新程序员更好地理解概念,这些概念将通过面试和整个职业生涯为他们提供帮助。

iOS NotificationCenter以更好的方式

应用程序开发中的常见模式是通知( NSNotification和NotificationCenter )。 通过通知,您可以将消息广播到多个侦听器。 在许多情况下这可能很有用。 一个常见的示例是,如果您有许多UIViewControllers都需要在模型更改时进行更新。 但是,我觉得使用NotificationCenter的标准方法是容易出错,复杂且冗长。 我主要使用另一种方法,您可以在其中创建自己的NotificationCenter版本。 首先,以NotificationCenter的正常使用为例: 扩展Notification.Name { 静态让didUpdateCar = Notification.Name(“ didUpdateCar”) 静态让didReceiveData = Notification.Name(“ didReceiveData”) } 类MyViewController:UIViewController { 覆盖func viewDidLoad(_动画:布尔){ super.viewDidLoad(动画) setupNotifications() } 私人功能setupNotifications(){ NotificationCenter.default.addObserver(自身,选择器:#selector(didUpdateCar(_ :)),名称:.didUpdateCar,对象:无) NotificationCenter.default.addObserver(自己,选择器:#selector(didReceiveData(_ :)),名称:.didReceiveData,对象:无) // …一长串清单 } deinit { NotificationCEnter.default.removeObserver(自己) } @objc私人函数didReceiveData(_通知:NSNotification){ //如果您在发送方更改了userInfo,则此操作无提示。 崩溃喜欢? 如果让数据= notification.userInfo为? [String:Int] { 用于数据{中的(name,ageInYears) print(“ \(名称)是\(ageInYears)岁。”) } } } } 类AnotherViewController:UIViewController { […]

带有`default`参数值的Swift协议

在一个非常常见的情况下,您有一个类 ,其中包含带有默认参数值的方法,并且您要对其进行测试。 Baz类{ func foo(bar:BarType,camp:CampType = CampType())->字符串{ 返回“世界” } } 首先编写协议,以便可以为类实现模拟,如下所示: 协议BazProtocol { func foo(bar:BarType,camp:CampType)->字符串 } 和模拟 : struct BazMock:BazProtocol { func foo(bar:BarType,camp:CampType)->字符串{ 返回“” } } 您希望模拟共享默认值,因此首先要在协议定义中设置默认值,最后得到类似这样的内容。 协议BazProtocol { func foo(bar:BarType,camp:CampType =“ Hello”)->字符串 } 但是您得到以下错误: default argument not permitted in a protocol method 有一种方法可以解决该限制。 扩展程序可以解救! 我们不会在Baz或BazMock上定义默认参数,但将使用协议扩展名 ,这是将定义默认值的唯一位置。 这样,同一协议的两个实现都具有相同的默认值。 扩展名BazProtocol { func foo( bar:BarType, camp:CampType = […]

扩展,私有和文件私有

封装是面向对象编程的四个基本原理之一。 访问控制是启用封装的设备的一部分[1]。 私有,文件私有,内部和开放是Swift中可用的四个访问控制。 这篇文章是关于我将如何使用扩展以及private和fileprivate来组织我的代码的简短说明,这导致了抽象。 在项目开始时很难进行抽象,尤其是在产品的所有功能和要求不清楚时。 在这里,我们组织代码的方式非常方便。 我从中受益的一件事就是使用扩展来组织我的代码。 随着项目的发展,这些扩展趋向于成为单独的类,结构或协议(在我的情况下主要是协议),并帮助我将自己的意图清楚地传达给其他开发人员。 让我们看一下这个新闻应用程序的示例,该示例具有两个集合视图选项卡,每个选项卡都显示某种类型的内容列表 TabA —显示来自某些集合的列表,但是没有完全定义需求。 TabB-显示最近添加的新闻文章,基于文章中嵌入的内容,UICollectionViewCell中将有一个媒体指示器(视频或音频)。 在本文中,我将重点介绍媒体指示器功能。 我们知道TabB的要求,此处显示了一个名为ArticleTeaser的视图模型(以1为例)。 它具有标题,文章的简短摘要以及文章中嵌入的媒体。 有一个计算属性mediaDisplayType ,它显示媒体是什么类型。 现在,让我们看一下另一个示例,该示例说明我们如何使用一些扩展来组织代码 现在,此扩展程序提供了从媒体列表中找到嵌入的媒体类型的功能。 这也使其他开发人员可以清楚地使用mediaThumbnailType fileprivate函数,该函数是此扩展的接口。 我的一位同事总是问我为什么您只有一个功能的扩展名? 答案是我倾向于将提供类/结构的特定行为的函数归类为扩展,即使它只是一个函数。 随着代码库的增加,这很方便。 现在,当TabA的要求到达时,我们注意到它还必须显示一些有关媒体类型的信息。 如果我们注意到扩展,我们使用的函数没有副作用,因此我们可以轻松地将其移入协议。 我们可以想到具有文件私有功能的这些扩展,就像我们编写的任何其他接口一样,但也可以作为在单个类/结构中使用的接口。 编码愉快! [1] https://en.wikipedia.org/wiki/Access_control

粒子发射器带来的乐趣

我喜欢HackingWithSwift网站和YouTube视频。 我认为保罗·哈德森(Paul Hudson)在用易于理解的术语和清晰示例来解释概念方面做得非常出色。 我一直想了解有关iOS动画的更多信息,以及寻找向iOS应用添加一些简单功能的方法。 斯威夫特问世期间 系列文章中有一篇关于Core Animation的文章,涉及绘制漂亮的白雪皑皑的背景。 在那篇文章中,我发现最有趣的是使用粒子发射器使雪花飘落。 我曾经在游戏中看到过粒子发射器,例如用于产生爆炸或魔术效果的游戏,但在非SpriteKit iOS应用中却没有。 这让我想知道可以使用粒子发射器创建什么其他效果。 粒子发射器是一种在应用程序屏幕上增加一点天赋的好方法,而无需在创建动画上进行大量投资。 在开始使用粒子发射器时,我首先创建了与Swift来临类似的降雪效果。 通过将CAEmitterLayer和CAEmitterCell与简单的渐变结合CAEmitterLayer ,可以创建一个非常简单的效果。 粒子发射器的代码相当简单,并从Swift的Advent中得到了充分利用。 要注意的主要元素是CAEmitterLayer和CAEmitterCell 。 让我们快速依次查看每个元素。 Apple文档将CAEmitterLayer描述为: 发射,设置动画和渲染粒子系统的层。 本质上,该层负责生成由CAEmitterCell定义的粒子(即雪)。 发射极层的重要属性是shape , position , size和mode 。 默认形状是point ,这意味着所有粒子都将从特定点发射。 还有其他几种形状选项,例如line , circle , rectangle甚至cuboid 。 发射器形状的大小和位置属性将影响其输出以及模式设置。 Apple文档将发射器模式描述为: 一个字符串,定义如何相对于发射形状创建粒子。 当前选项是“点”,“轮廓”,“表面”和“体积”(默认)。 在我们的粒子视图中, CAEmitterLayer被用作基础层。 但是,生成粒子的实际工作是由CAEmitterCell类完成的。 适用于CAEmitterCell状态的Apple文档: CAEmitterCell类表示由CAEmitterLayer对象发射的粒子的一种来源。 发射器单元定义了发射粒子的方向和属性。 发射器单元可以具有一个子单元阵列,该单元可以使粒子本身发射粒子。 可以将多种运动和时间属性应用于单元格。 我们将在后面的部分中进一步介绍这些内容。 降雪发射器中使用的主要参数是birthRate , lifetime , birthRate和birthRate 。 […]

在Swift中实现编程语言—第5部分:Main函数

这是“用Swift编写编程语言”教程系列的第五部分。请务必阅读第4部分。 在之前的教程中,我们完成了为计算器实现Lexer和Parser的工作。 现在,剩下的一切我都可以简单地遍历AST并“解释”一些输出。 所以……快到了! 您可能已经注意到,我们在解析时创建的Nodes ( Float和InfixOperation )很容易将两个值都评估为Float值。 因此,要评估AST,我们要做的就是向Node协议添加一种协议方法,以解释每个单个Node并在Node结构中实现它: 协议节点{ func interpret()throws-> Float } // … 扩展浮动:节点{ func interpret()throws-> Float { 返回自我 } } struct InfixOperation:节点{ // … func interpret()throws-> Float { 让左=尝试lhs.interpret() 让权利=尝试rhs.interpret() 切换op { 案例.divideBy: 返回左/右 案例时间: 返回左*右 大小写减号: 返回左-右 案例.plus: 返回左+右 } } } 就是这样,现在我们已经准备好创建我们的main函数,让我们称之为run : func run(code:String)抛出{ let令牌= Lexer(代码:代码).tokens 让解析器=解析器(令牌:令牌) 让ast […]

您不应该在快速结构中存储什么?

答:参考类型。 您在任何地方搜索都会发现值类型和引用类型之间的差异。 但是,当您将两者混在一起时,文档尚不清楚。 该结构将失去其(表观)不变性。 让我们用一个例子来解释一下:假设我们正在使用一种结构来存储与广告相关的配置 struct AdConfig { var prefetchCount:Int var wrapperView:UIView? } 公司要求我们在每个屏幕上展示广告,因此我们决定使用静态默认值: struct AdConfig { var prefetchCount:Int var wrapperView:UIView? static let`default`:AdConfig = AdConfig(prefetchCount:10, wrapperView:UIView(frame:CGRect.zero)) } 太棒了! 现在我们可以使用AdConfig.default 无需显式创建实例的任何位置。 现在,在一个屏幕中,我们有不同的设计,因此,我们将复制默认实例并修改值: var customConfig = AdConfig.default customConfig.wrapperView?.backgroundColor = UIColor.red AM! 现在,无论您走到哪里,所有广告现在都具有红色背景,即使我们的默认变量是let常量并且应该是不变的。 您可以在操场上跑步: 因此,请勿在您的结构中存储以下任何内容: 迅捷类实例 任何NSObject子类 闭包(是的,它们是参考类型) 如果必须的话,请确保您了解它的含义(以及调试数小时和数小时来修复一些奇怪的错误)。

创建自己的CocoaPods库

介绍 作为iOS开发人员,您可能在项目中使用了一些CocoaPods库,并且您可能非常熟悉如何安装它们并调用它们的方法。 但是,您是否梦想过通过分发自己的pod(CocoaPods库)为iOS开源社区做出贡献? 想象一下,许多iOS应用程序都将使用您的超棒库,这不是太棒了吗? 在本教程中,我将向您展示如何分发一个简单的pod。 除此之外,您还将学习如何利用Travis CI和Codecov来确保您的Pod可靠可靠。 总览 有多种创建吊舱的方法。 最常见的方法是遵循CocoaPods官方文档Using Pod Lib Create,基本上,您可以使用以下命令快速引导Xcode工作区以开发新的Pod: > pod lib创建[pod名称] 在自举的工作区中,我不喜欢的一件事是,与单元测试有关的代码嵌套在示例目标内部,这对我来说没有意义。 经过一番尝试和错误之后,我找到了一种从头开始创建pod并很好地组织单元测试和示例代码的方法。 以下是创建窗格的所有步骤的快速概述: 设置Xcode项目和必要的目标 链接到Github 实施吊舱 编写单元测试 配置Travis CI和Codecov 发布广告连播 在撰写本文时,我正在使用以下软件: macOS Mojave 10.14.3 Xcode 10.1 斯威夫特4.2 椰子足1.6.0 好的,让我们开始吧! 设置Xcode项目和必要的目标 实际上,在创建项目之前,有一项重要的工作要做,让我们命名Pod SwiftyLib ,并确保未在CocoaPods上使用该名称,幸运的是,该名称尚未提交,因此我们可以继续进行。 创建一个Cocoa Touch Framework Xcode项目 在后台,CocoaPods库是Cocoa Touch框架库。 启动Xcode并创建一个新项目,选择Cocoa Touch Framework 。 输入名称SwiftyLib   ,选中Include Unit Tests复选框。 在下一页上,选择项目位置,不要Create […]