Tag: 编程

大中央派遣(GCD)

GCD是用于管理任务执行的库,对于开发人员而言,异步编程使开发更容易,更安全。 异步允许任务同时执行,而不是通过在不同线程/进程上并行运行来阻止当前执行线程。 通过在后台线程上处理长时间运行的块,同时仍允许用户与主线程上的UI进行交互,它使应用程序具有更高的响应速度。 术语 串行和同步是同义词,并发和异步是可互换使用的。 主队列-处理应用程序的所有UI和未明确要求在后台队列中运行的代码的队列。 串行-串行队列中的任务一个接一个执行,一次仅执行一个任务。 任务按照插入队列的顺序执行。 并发-允许您并行执行多个任务。 任务以它们添加到队列的顺序开始,但不必等待彼此开始执行。 执行和完成的顺序不是预定的。 dispatch_queues 有两种类型的调度队列(队列由dispatch_queue_t表示),串行的和并发的。 要使用串行队列,请使用主队列 让mainQueue = dispatch_get_main_queue 或创建自己的 让serialQueue = dispatch_queue_create(“ @ anthonyprograms”,DISPATCH_QUEUE_SERIAL) 使用并发队列时,有多种选择:使用系统队列或创建自己的队列。 有四个优先级不同的系统队列,从最高到最低分别是: DISPATCH_QUEUE_PRIORITY_HIGH DISPATCH_QUEUE_PRIORITY_DEFAULT DISPATCH_QUEUE_PRIORITY_LOW DISPATCH_QUEUE_PRIORITY_BACKGROUND 优先级指出哪个任务将首先运行,优先级越高,它执行得越早。 让systemConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0) 您可以创建自己的 让currentparallelQueue = dispatch_queue_create(“队列”,DISPATCH_QUEUE_CONCURRENT) 将任务提交到队列 将任务提交到队列时,它可以同时运行或串行运行。 运行dispatch_sync(queue)依次运行该块,该块等待该块完成,然后再继续执行下一个任务。 并且dispatch_async始终是异步的。 只是您将所有UI块排队到同一队列中,因此不同的块将按顺序运行,但与数据处理代码并行运行。 队列示例 输出:“ polo \ n marco”。 这是因为GCD正在将异步代码块添加到队列中并继续运行该代码。 但是,当您更新UI时会发生什么? 在处理UI的后台线程上运行代码将导致崩溃。 为了在后台执行某些块,然后使用该结果来更改UI,必须首先获取主队列。 团体 假设您有一些更复杂的事情,需要更多类型的处理,并且只想在所有任务完成后更新UI。 这样,您可以使用dispatch_group_t。 […]

开始进行Swift编程第9部分-基本协议,扩展和下标

在上一篇文章中,我们介绍了类型转换,安全展开可选内容和访问控件。 Swift编程第8部分开始-类型转换,安全解压缩可选项和访问控制 在上一篇文章中,我们讨论了初始化,反初始化,覆盖和引用计数。 medium.com 没什么困难,对于您中的某些人而言,也许最好不过是适度的,因为有了访问控制的概念。 这篇文章可能会使事情再次升温,但这又仅仅是因为实际的应用程序用例。 我将尽力以一种可以帮助您理解所有内容以及何时应在何处使用所涉及的主题的方式来解释事情。 我知道有些教程可以直接跳转并提供扩展,但是我不会。 扩展是利用您已经知道的内容做更多事情的基础,因此,我决定最好从协议开始。 因此,让我们深入。 好的,所以协议和扩展声音令人生畏,Apple提供的定义在您开始时并不能消除浑水。 这个定义直接来自苹果的书: 协议定义了适合特定任务或功能的方法,属性和其他要求的蓝图。 然后,该协议可以由类,结构或枚举采用,以提供这些要求的实际实现。 满足协议要求的任何类型都被称为符合该协议。 你们中有些人可能已经了解到,其他人可能仍然会挠头。 不用担心,现在,让我们暂时忘记该定义,我有一个使用棒球的指导来指导我们进行定义。 在棒球中,我们有不同的位置,例如击球手,投手,接球手,垒手,外野手,教练和裁判员。 如果您对棒球有任何了解,您就会知道团队中的每个人都有自己的角色,每个人都擅长于该角色。 我们不能只是让三垒手成为投手,或者让裁判成为外野手。 第一种情况很难,因为团队喜欢为一垒手雇用左撇子,为三垒手雇用右撇子。 另一个似乎不是一个好主意,因为两队之间的裁判是中立的。 如果每个玩家都是一堂课, 那么他们如何玩游戏就由协议定义。 让我们看看它在代码中的外观。 扩展以简单的概念而得名。 扩展实质上是将功能扩展到类,结构或协议。 关于它们的使用方式,我将引用Swift中的Foundation库。 Foundation有一个名为UITableView的类。 UITableView本身仅处理显示表视图。 但是,我们可以通过给它一个名为UITableViewDataSource的扩展来扩展其功能。 这为采用此协议的类提供了提供数据如何在表视图内部显示的上下文的能力。 上图是扩展的一个很好的例子。 通过单击“无选择”,您可以打开当前布局的树。 这使您可以通过单击树的任何部分来浏览代码,Xcode将专注于该代码。 通过使用//MARK: — Properties ,可以在属性上方创建一条水平线,同样可以使用 //MARK: Properties —在属性下方放置一条水平线。 或者,您可以在上方和下方都设置一个,但是我通常只在上方放置一个,以将其分成这样的部分。 您可以选择最有意义的选项。 有关更多信息,请查看Apple的标记文档。 好的,只是我想离开这里的提示,回到扩展。 除了将您的代码分成逻辑区域外,它们还做了其他一些事情,这也成为我成为协议狂热者的原因,并尽可能尝试使用它们。 因此,协议对于团队来说很棒,从一开始就显而易见,但是您可能会问自己,如果您是一个单独的开发人员,为什么还要使用协议? 您知道一切都会做什么,并且不介意在一年后回到您的代码以发布更新时重新学习。 特别是如果这意味着必须编写更多的代码,这对于您的应用正常运行并不重要。 还记得Fielder协议吗? 如果我告诉您不必编写协议要求,也不必单击红色的停止符号以使它在每次使用协议的情况下都实现每个方法存根,该怎么办。 那您想要协议吗? 纯粹的事实是,在上面的示例中,如果您在同一实现中使用darn编写7次6个属性和4个方法,那将是疯狂的,那就是42个属性和28个方法,更不用说每种方法所涉及的逻辑了。 对我来说听起来像是折磨。 […]

了解Apple的二进制属性列表格式

标记字节有时足以完全识别一个对象。 例如,空值的标记等于零,布尔值的标记为0(如果为false),如果标记为0,则为0x09(如果为true)。 所有其他对象都可以通过其4个最高有效位来唯一标识(从现在开始,我将使用最左和最右的术语代替MSB和LSB)。 例如,整数的最左4位是0001(0x1),而对于字符串,它们是0110(0x5)。 剩下的最右边的4位表示大小信息,即,此类型的实际值将在标记之后占用多少字节。 在某些情况下,如果对象足够小,则会立即在最右边的4位中对大小进行编码。 例如,ASCII字符串“ Hello”将被编码为0x55,然后将跟随实际的字符值。 在其他情况下,填充标记(0x0F)与对象标记进行“或”运算,表示下一个字节在实际值字节之前编码大小信息。 更具体地说,如果标记的最右4位等于1111(0xF),则下一个字节将具有以下结构: 其最左边的4位等于0001(0x1) 它的最右边的4位告诉我们编码对象大小需要多少字节。 如果最右边的4位包含值x ,则大小将需要pow(2,x)字节 然后,跟随pow(2,x)个字节,应该以大字节序读取该字节,以提供对象的实际大小。 之后,将遵循对象的实际值。 例如,字符串“ This is a long string”包含21个ASCII字符。 标记为0x5F,后跟字节0x10 (因为pow(2,0)= 1,并且1个字节足以编码值21),然后是0x15 (十六进制的十进制21),然后是21个字符其他。 对应于诸如整数,实数,字符串之类的对象的标记紧随其后的是代表其实际值的多字节序列(例如,如上所述的单个字符串字符)。 但是,并非总是如此。 对于对象容器,例如数组和字典,标记字节后跟对象引用 只是偏移表的偏移量(请参阅下一节)。 这样的偏移量是object_ref_size 由bplist尾部确定的长字节,从偏移量表的开头开始计数。 因此,容器元素只是大小为object_ref_size的引用,它指向偏移表中的某个位置,该位置本身就是offset_table_offset_size 字节长,指向对象表,特别是指向与单个对象相对应的标记。 下一节中的示例将消除所有混淆。 此技术将实际的多层结构平面化,并允许所有对象具有固定的大小。 因此,我们始终知道,值0xA5的标记后面是5 * object_ref_size字节。 这种间接级别也允许基本的压缩形式。 当容器的值完全相同时,它们可能指向相同的偏移表偏移量。 容器示例: 0xA5 — 5个元素的数组。 在标记后没有立即找到这5个元素的值。 相反,在标记之后,我们找到5个对象引用,它们充当偏移表的偏移量。 遵循这些引用后,可以在对象表中找到其各自的字节标记的偏移量,在该表中可以找到实际值(或者如果标记再次是容器,则遵循相同的过程)。 0xAF 0x10 0x0F —由15个元素组成的数组(与上面相同,但是现在大小信息不适合4位)。 随后是15个对象引用。 0xD6 —由6个键值对组成的字典。 […]

Swift服务器端:简介

作为有抱负的iOS开发人员,服务器端编程并不是我要深入研究的主题之首。 但是,研究母语的多功能性和潜力激发了我的灵感,激发了我的创造力。 为什么iOS开发人员会考虑在服务器端进行编程? 为您的iOS应用创建自己的后端,而不是使用第三方 在您的网站上展示完整的应用程序,作为您产品组合的一部分 轻松管理您的内存占用量 使用客户端和服务器组件丰富您的项目 主要玩家 这里有三种出色的服务器端Swift服务:Perfect,Kitura和Vapor。 对于本教程,在创作者Tanner Nelson在Meetup上介绍了框架之后,我决定使用Vapor。 “ Vapor是用于开发基于云的应用程序的模块化服务器端框架,它利用Swift中的类型安全性,并提供模式匹配以简化路由。 该框架的共同开发者Logan Wright看到了Swift在服务器上的潜力,因为它已经可以容纳iOS开发人员,并且可以在不同平台之间实现代码共享。” -http://www.infoworld.com/article/3088305/application-development/server-side-developers-take-a-shine-to-swift.html 我该如何开始? 首先,请确保已安装Xcode 8,因为Vapor需要Swift 3。 由于Vapor使用命令行,因此请在Xcode中选择当前命令行工具。 导航到Xcode->“偏好设置”菜单中的“位置”。 这样我们就可以使用终端来构建和运行我们的代码。 在“命令行工具”下拉菜单中选择最新版本。 Vapor提供了一个命令行工具集。 首先运行以下命令,以确保您具有正确版本的Xcode和Swift: curl -sL check.vapor.sh | 重击 如果是这样,您应该获得一个绿色的复选标记。 如果没有,您将需要更新。 Swiftenv是一个很好的版本管理器。 一旦拥有正确的版本并且兼容性检查返回true,就可以安全地安装Vapor Toolset: curl -sL工具箱.vapor.sh | 重击 对我来说,安装非常快。 安装完成后,我通过在终端中键入“ vapor”来检查一切是否正常。 由于未执行命令,因此收到命令列表和错误。 现在剩下的就是创建一个项目和代码。 要创建一个新项目,只需导航到您要存储该项目的目录并运行以下命令(“ HelloWorld”是我的项目的名称。您可以在其中使用任何内容): $蒸气新的HelloWorld Vapor在当前目录中创建一个项目,并使用Swift Package Manager下载并安装所有必要的依赖项。 导航到您的项目目录。 Vapor安装的文件遵循“模型”,“视图”,“控制器”模式,每个都有一个文件夹。 对于此项目,我们将需要导航到并打开将首先运行Vapor的“ main.swift”文件。 […]

Swift 3:永久存储数据

一个带有UserDefaults的。 永久数据存储是iOS应用程序开发人员掌握的一项重要技能。 对于大多数应用程序,您将要存储一些有关用户的信息,以便当他们返回应用程序时,即使关闭应用程序后,它们也可以立即获取其数据。 有多种方法可以实现此目的,我们正在研究本节中最简单的方法之一。 因此,我们将在这里使用的是UserDefaults。 您可能会想到,它用来存储有关该特定用户的一些基本信息,但实际上您可以用来在设备上本地存储任何类型的信息。 这也很容易设置。 打开一个新的xcode项目,然后在viewDidLoad()方法中键入以下代码。 我们将字符串(或任何项目)保存到UserDefaults中,该变量设置了一个名为“ key”的变量,并为其提供了一个值“ String”,当我们想取回该值时,我们只需使用“ key”即可。 当您运行该应用程序时,您将在日志中打印出您的字符串。 现在,为了确保已确实保存了数据,让我们再次运行该应用程序,但是这次我们将注释掉保存部分。 这样做完全相同(再次检查日志),这意味着数据将永久存储,并且只要加载应用程序就可以访问数据。 基本上,您可以将任何类型的数据存储到UserDefaults中,例如在对象中,如String,Date,Array,Integer甚至是Boolean。 为此,我们需要创建UserDefaults的全局实例。 再次注释掉存储值部分并运行应用程序,您将发现数据已永久存储。 检索对象时,结果是可选的。 这意味着您可以接受可选性,也可以将其类型转换为非可选类型,然后使用nil合并运算符处理缺失值。 例如: 因此,我们在这里检查的是,我们能够获取名称对象并将其转换为字符串,如果存在,则将其打印出来。 这是检查对象是否存在以及对象是否为某种类型的更安全的方法。 这就是关于UserDefaults的全部内容。 注意: NSUserDefaults已重命名为UserDefaults standardUserDefaults()已重命名为standard

系统设计,第5章:数据库索引

聚簇与非聚簇,聚簇索引,非聚簇索引,聚簇和非聚簇索引 在此博客中,我们将研究后端工程师如何处理从数据库中快速检索记录。 让我们尝试以简单的角度来理解事物是如何工作的以及什么是集群索引和非集群索引。 集群索引 我们都已经看到了座机时间,以前我们在家里有电话簿,每当需要任何数字时,我们都需要按字母顺序查找并找到所需的数字,也就是说,您知道什么是集群索引。 电话簿(单个参考—按字母顺序)—组织数据 集群表的最大优点之一是,数据是通过存储子系统中的集群键进行物理排序的。 您可以将“聚簇表”与传统电话簿进行比较:电话簿按姓氏聚类/排序,这意味着Abhishek的姓氏在Tarun之前,而Tarun在Umesh之前。 因此,聚簇表与没有物理排序顺序的堆表完全不同。 让我们尝试通过一些图表来了解集群如何在后端工作。 下面是使用群集索引的员工数据库的示意图。 非聚簇索引 我们从上学的时候就知道了这一点,当时我们过去经常看书的索引,并且能够从书的最后一个主题索引或书的索引中找出哪个页面需要寻找哪个主题。 “最后一本书”(索引参考)-基于页面的内容-多个主题可以具有相同的索引。 聚集索引节省了我们必须在非聚集索引中执行的其他I / O操作,以获取行数据。 这是因为完整的行数据驻留在聚簇索引叶块中,而只有行定位符存储在非聚簇索引叶块中。 因此,我们保存了一个额外的I / O来到达该行。 这表明使用聚簇索引的点查找通常比非聚簇索引更快。 对于UNIQUE和NON-UNIQUE索引类型都是如此。 同样, 在范围扫描的情况下,聚集索引将更快 。 如果扫描恰巧检索大量数据,则群集索引和非群集索引之间的性能差距可能非常大。 缺点: 在非聚集索引上查找会变得很昂贵。 假设在A列上有一个聚集索引,在B列上有一个非聚集索引。一旦在B列的键值上探测了非聚集索引,我们将从叶子中获得聚集索引键(A列)的值。块。 然后,使用列A的索引键值来探查聚簇索引(这也是B树遍历),并从聚簇索引的叶块中获取相应的行。 每次更新聚类密钥时,由于非聚簇索引存储聚类密钥,因此也需要对非聚簇索引进行相应的更新。 宽/宽聚类键将增加非聚簇索引的大小,也将增加索引叶块中每个条目的大小。 因此,每个块将打包较少的条目,这将增加磁盘I / O —必须读取更多的索引页/块。 优点: 聚集索引要求以排序的顺序(在聚集键上)物理存储行数据。 表中的INSERT(实际上是这里的聚簇索引)必须维护“排序顺序”的不变性。 因此,很有可能必须四处移动行(行在一个块内或跨块移动)以适应新的插入。 如果非聚集索引正在存储行定位器,那么每个这样的INSERT也将需要更新非聚集索引,因为行定位器会由于行移动而发生变化。 但是因为非聚集索引存储聚集索引键而不是行定位符,所以由于行移动而不需要进行此类更新。 查询优化器如何使用索引 精心设计的索引可以减少磁盘I / O操作并消耗更少的系统资源,从而提高查询性能。 索引对于包含SELECT,UPDATE,DELETE或MERGE语句的各种查询很有帮助。 考虑E mpDataBase2018(Imaginary)数据库中的查询SELECT标题HireDate FROM HumanResources.Employee WHERE EmployeeID = […]

Swift中的引用和值类型

在这篇文章中,我们将研究引用类型和值类型之间的差异。 我们将介绍这两个概念,看看它们的优缺点,并研究如何在Swift中利用它们。 参考类型 引用类型 :一种类型,一旦初始化,将其分配给变量或常量,或传递给函数时,将返回对相同现有实例的引用。 引用类型的典型示例是对象。 一旦实例化,当我们分配它或将其作为值传递时,实际上是在分配或传递对原始实例的引用(即,它在内存中的位置)。 引用类型分配据说具有浅表复制语义。 在Swift中,使用class关键字定义对象: 类PersonClass { 变量名称:字符串 init(name:String){ self.name =名称 } } var person = PersonClass(name:“ John Doe”) 值类型 值类型 :一种类型,在分配给变量或常量或传递给函数时会创建新实例(副本)的类型。 值类型的典型示例是原始类型。 常见的基本类型(也是值类型)是: Int , Double , String , Array , Dictionary , Set 。 实例化后,当我们分配它或将其作为值传递时,实际上是在获取原始实例的副本。 Swift中最常见的值类型是struct , 枚举和元组可以是值类型。 值类型赋值据说具有深层复制语义。 复制语义 我将通过一个实际的例子来说明复制语义之间的区别。 假设我们正在使用通用树数据结构: 类Node { 出租价值:T var左:节点? var对:节点? 便利init(值:T){[…]} init(值:T,左:节点?,右:节点?){[…]} […]

驯服iOS中的大量控制器第3部分

欢迎来到“ 驯服iOS中的大量控制器 ”的最后一部分。 强烈建议您先阅读本系列的第1部分和第2部分,然后再继续本文。 在前面的文章中,我们将UITableView控件的数据源提取到了一个单独的类“ ShoppingListDataSource ”中。 这将所有数据源功能从ShoppingListViewController移到了数据源的指定类中。 这项技术极大地帮助我们减小了控制器的尺寸,并将其放置在正确的位置。 当用户选择购物清单时,他/她被发送到杂货项目屏幕,在该屏幕上显示所选购物清单的所有相关项目。 这意味着我们需要为杂货项目创建一个单独的数据源。 GroceryItemsDataSource看起来与ShoppingListDataSource完全一样,唯一的区别是GroceryItemsDataSource将处理GroceryItem类型的商品,而不是ShoppingList,如下面的屏幕快照所示: 一种替代方法是创建适用于所有类的通用数据源和数据管理器类。 通用的UITableViewDataSource和数据管理器: 通用的TableViewDataSource将独立于类实体,单元格或与对象关联的数据管理器/数据提供程序的类型。 UITableViewDataSource的声明如下所示: class TableViewDataSource :NSObject,UITableViewDataSource,FetchedResultsDataProviderDelegate { 如您所见,TableViewDataSource是一个通用类,您可以在其中传递单元格和实体的类型。 由于我们正在使用CoreData,因此我们的实体类继承自自定义协议ManagedObjectType,这是我们的自定义类型。 TableViewDataSource初始化程序采用所有必需的参数,如下所示: init(cellIdentifier:String,tableView:UITableView,dataProvider:FetchedResultsDataProvider ,cellConfigurationHandler:(CellType,Entity)->()){ self.cellIdentifier = cellIdentifier self.cellConfigurationHandler = cellConfigurationHandler self.dataProvider = dataProvider self.tableView = tableView super.init() } 需要注意的一件事是dataProvider参数,它也是FetchedResultsDataProvider的通用类型。 让我们检查ShoppingListTableViewController中的代码,该代码声明了数据源和数据提供程序。 私有var dataSource:TableViewDataSource ! 私人var dataProvider:FetchedResultsDataProvider ! 接下来,我们将使用适当的信息初始化dataSource和dataProvider属性。 覆盖func viewDidLoad(){ super.viewDidLoad() self.dataProvider = FetchedResultsDataProvider(managedObjectContext:self.managedObjectContext) self.dataSource […]

迅捷范围

低调…大调 Swift编程语言中的集合将相同类型的元素组合在一起。 Swift集合(数组,集合和字典)以与具有相似兴趣或个性的人一起闲逛并组成小队的方式存储值。 范围(…)是原始班级 Apple将范围定义为“可比较类型上的间隔”,通常是整数(Int)或Double类型。 但是,范围也可以被视为集合-索引的集合。 而且由于Swift集合都具有索引,因此Arrays,Sets和Dictionary Arrays是非常基础级别的索引(又称Ranges)集合: 分数= [88,90,88,93,97]是… 数组 = [0,1,2,3,4]→ 0…4 体育= [“足球”,“篮球”,“橄榄球”,“足球”)是… 设置 = [0,1,2,3]→ 0…3 州= [纽约:纽约州,加利福尼亚州:加利福尼亚州,内华达州:内华达州]是… 字典数组 = [0:1,1:2,2:3]→ 0…2 有两种类型的范围: 范围可以做什么: 范围可以一次更改数组中的多个值: 在上面的示例中,两个项目或值被添加到shoppingList数组中,特别是在索引范围3…4处。 删除“香蕉”和“冰淇淋”,​​并替换为“奶酪”和“葡萄”。 在这里,Range使更新数组的多个值更有效,因此我们不必通过一次执行shoppingList [index] =“ new item”来一次更改一个索引的值。 如果要删除的项目总数不等于要添加的项目总数,这也可以工作。 范围可以定义条件: 有时,我们可能希望我们的程序仅在“某些”条件为真或假的情况下运行。 对于可以用数值表示的条件,例如游戏中的功率水平,天气应用程序中的温度或车辆的速度,我们可以使用Range设置必要的参数。 在上面的示例中,速度的条件写为布尔语句(> = 0 && <= 90),但是我们可以将其转换或读取为范围从0开始直至90(0…90)的范围。 我们可以根据字符串值创建一个范围: 在上面的示例中,我们通过从较大的字符串(“ OCTOBER”)中隔离出一组值(“ TOBE”:索引0、1、2、3)来创建“字符串之外的值”。 然后,我们为索引范围为1…3的新子字符串定义索引参数。 接下来,将定义一个半开范围值类型(.. <)的subRange,它表示在对String调用subRange时,获取Range的String值,该值从索引1开始,但不包括3(1…2)。 这给出值“ OB”。 […]

iOS面试问题:基础知识

是的,许多伟大的作者已经讨论了这个话题,他们有很多的问题和答案。 在我的这篇文章中,我没有做任何不同的事情,尽管我认为分享我的采访经历会很棒。 那么从哪里开始呢? 诚实的答案将来自“ 基础知识 ”。 而且基础是Oops概念。即面向对象的编程概念。 如果面试官是有经验的人,他或她肯定会从此开始。 因此,在本文中,我们将介绍Oops概念。 对于与此相关的问题,我们应该准备好至少一个衬纸答案,并在需要时提供示例。 问:什么是面向对象编程? 面向对象编程是一个概念,它涉及现实世界中的对象以及操作这些对象的方法。 目标C / Swift中的基本概念: 类 :类是一组属性和方法。 //迅速 类Person:NSObject { var firstName:字符串? var lastName:字符串? var age:整数? func printFullName(){ //一些要打印的代码 } } // Objective-C @interface Person:NSObject @ property(强原子)NSString * firstName; @property(强原子)NSString * lastName; @property(assign,atomic)int age;-(void)printFullName; @结束 对象 :对象是类的实例。 //迅速 var person1 = Person()//目标C 人* person1 = […]