›也可以 在此链接的我的博客上找到本文 。 计时器允许我们在一个或多个计时器间隔后执行一些代码。 有多种类型的时钟可用于创建计时器,即使所有这些时钟显然都以相同的速率运行,它们的行为仍然不同。 我们可以列出以下计时器类型列表: 实时时钟或RTC 。 它是一个计算机时钟(通常为集成电路形式),用于跟踪当前时间。 用户可以任意更改此时钟,而NTP(网络时间协议)则最好使其与外部参考保持同步。 它的值每秒增加一秒钟,但有时可能会更快/更慢或向前跳跃( 这要感谢Gavin Eadie,这使我意识到时钟永远不会向后运行.NTP同步发现时钟在运行如果运行速度快,则在尝试与外部源同步时应放慢速度,直到“实时”赶上 。 单调计时器 。 它的计数器通过使用计时器中断发送到CPU的物理信号递增。 在Apple平台上,此值由Mach内核通过mach_absolute_time()返回。 返回值取决于CPU,因此您不能只将其乘以一个常数就可以得出真实值。 相反,您应该调用系统提供的转换函数将其转换为真实值(CoreAnimation有一个方便的方法:CACurrentMediaTime())。 它在启动时被重置的事实使得获取现实世界中流逝的时间并不那么有趣,但是它是测量两个时间间隔之间差异的最精确方法。 启动计时器 。 它只是一个特殊的单调计时器 ,在系统进入睡眠状态时不会暂停。 获取其值的最常见方法是从终端调用uptime函数。 在Apple平台上,创建计时器的最常见方法是使用NSTimer类。 实际上,它只是围绕单调计时器的包装。 因此,使用NSTimer可能会以无法预料的方式结束,特别是在iOS上,在如上所述的某些极端情况下,机会性的资源使用可能会结束。 为了充分理解NSTimer,我们需要谈一些NSRunLoop; 一旦启动,每个应用程序都会创建第一个NSThread,称为Main Thread; 每个线程都有一个关联的运行循环,该循环管理输入源,例如鼠标,键盘,触摸,连接……以及显然是我们的计时器。 您可以将RunLoop视为等待新消息并将其传递给适当的收件人的邮箱 :它基本上是一种消息传递机制,用于异步或线程间通信。 一些平台(如Windows)将其称为Message Pump,但内部概念仍然相同。 实际上, 运行循环代表了命令行 应用程序 与交互式 (通常是基于UI) 应用程序 之间的主要区别 。 当第一个使用参数启动时,执行它们的内容,然后退出,一个交互式应用程序等待用户输入,对此做出反应并再次等待。 每个线程只有一个Run循环; 一个运行循环由一组要监视的输入源(键盘,触摸等)和一组要通知的观察者组成。 隐式或显式地使用特定的运行模式初始化运行循环。 在其生命周期内, 仅监视与该模式关联的源并允许其传递事件; 仅将与该模式关联的观察者通知新数据。 Cocoa / UIKit定义了几种类型的模式:在iOS上,有一种特殊的模式称为UITrackingRunLoopMode:在控件中进行跟踪时设置。 […]
Swift中的Tuple是什么: 元组是swift中可以容纳多个类型的复合类型。而非常简单的元组是可以容纳零个或多个类型的类型。 像一个元组可以容纳Int String bool或任何其他数据,即使它可以容纳其他复合类型和名称类型。 在苹果文档中: 元组类型是用括号括起来的零个或多个类型的逗号分隔列表。 了解元组是值类型而不是引用类型更重要。 句法 : var(元组名称)=(type1,type2) var myTuple =(100,“ String”)//这里的元组具有2个值Int和String 元组可以创建两种方式的隐式定义类型或显式定义类型: 明确定义: var tupleOne:(Int,String)=(12,“ Ekram”) 在这里,我们明确定义了元组类型(Int,String) 明确定义的类型: var tupleTwo =(“ Ekram”,true) 这里这个元组上的两个元素两个是字符串,另一个是布尔 使用名称类型创建: 我们也可以这样定义类型元素名称 var tupleTwo =(name:“ Name”,isOky:true) 访问元组: 我们可以通过两种方式访问元组元素 按名字 例: var tupleTwo =(name:“ Name”,isOky:true) 现在我们可以像这样通过名称访问这两种类型 var name = tupleTwo.name var nameIsOky = tupleTwo.isOky 按索引 我们可以像这样通过它们的索引访问元组元素 创建一个元组 var tupleThree […]
开始: 一切都始于我三年级时,我报名参加了Swift课程。 在此之前,我对计算机语言的了解很少,仅了解一点Python和C。 原因: 我报名参加该课程的唯一原因是我是Apple的忠实粉丝,我喜欢他们给我带来的舒适的产品,硬件和软件的高度兼容性,美观的外观等。 我只想靠近苹果。 从班级中学到: 众所周知,这些课程仅讨论基本内容,例如如何使用UITableView,UIView,UIButton等。 这意味着您发布应用程序还有很长的路要走。 是的,是的,等等,阿诺有什么意义? 那是您需要分享的重要内容吗? 您说的没那么重要,但是让我决定发布应用程序的主要原因是与讲师的谈话。 当时我很高兴通过这门课程,我只想感谢讲师带领我进入Swift的大门。 他告诉我:“当您最终看到您的应用程序出现在App Store中时,您所获得的快乐就是您无法购买的。” 坐下来开始编码: 第一步真的很重要,不要再担心可能的障碍,只需抓一把椅子,倒一杯咖啡,坐下来开始编码。 大多数人都停留在第一步中,没有什么可担心的,只是随便打滚就可以了。 您会惊讶于开始编码后出现了多少个想法。 解决问题: 编写应用程序的方法并不总是一帆风顺,但最重要的是不要轻易放弃。 遇到问题时,请尝试调查没有该代码的网站:堆栈溢出 , 您的大部分问题都可以在那儿解决,或者从椅子上坐下来休息一下,做些编码以外的事情,无法说出原因,但是在我的情况下,当我洗个澡或在街上走路时,解决方案常常就出来了。 尝试: 有勇气尝试新事物。 以我自己为例,我从未学习过任何计算机绘图程序,因此在应用程序图标设计方面,这对我来说是巨大的痛苦。 那时,我只有三种选择。 1.雇用某人为我绘图。2.问一个了解计算机绘图的朋友。3.自己绘图。 我之所以选择第三项,是因为这是我将学到最多的唯一方法。 你真的相信那头牛吗? 当然不是,因为聘用某人来画画的价格不是我负担得起的,我是一个孤独的人。 所以我必须自己做,但这实际上是这三个中最好的选择,因为现在我学会了如何使用Sketch,而且我确定我会在以后的开发中使用它。 任何方式只要记住要面对障碍,不要害怕尝试新事物,那是改进的唯一捷径。 发行后: 我的App被Apple批准后,每当我看到我的App出现在App Store中时,我就会被幸福的狂喜所支配。 讲师说的对,这确实是您买不到的东西。 即使检查App Store Connect中的下载计数也是一件有趣的事情。 结论: 总而言之,发布一个应用程序并不难,只要跳入该应用程序就可以了。 随便吧〜
本文是Heimdall源代码的简要概述,并说明了为Vapor Web Framework编写第三方插件的过程。 去年,一位导师建议我为Vapor Web框架编写一个记录器。 最初,这似乎是一个复杂的任务,但结果再简单不过了。 让我们创建一个插件! 创建一个Swift包 蒸气插件必须是快速软件包,因此可以使用Swift Package Manager导入。 因此,首先需要在终端上运行以下命令来创建一个快速包。 麦克迪尔·海姆达尔 光盘海姆达尔 swift package init –type可执行文件 这将创建以下目录结构。 删除Sources目录中的main.swift文件。 Heimdall只是2个快速文件,而且少于200行代码! 以下是这两个文件的说明,没有实现细节。 如果您想查看所有代码,请参考github repo。 记录仪 HTTP记录器做什么? 它访问有关每个请求和响应的信息,例如状态码,HTTP方法等,并将其写入文件。 您需要创建一个“中间件”,该中间件针对每个请求运行,并将数据简单地写入文件。 以下代码片段显示了没有实现细节的基本中间件。 类记录器:中间件{ var path:字符串=“〜/ Logs / logfile.txt” //此方法针对每个Web请求运行 公共功能响应(请求:请求, chainingTo next:Responder)throw-> Response { //从响应对象访问数据 writeToFile(dataToBeLogged) } func writeToFile(path:){ //编写写入文件的快速代码 } } 记录仪与蒸气项目集成的提供商 现在您有了一个记录器,但是其他开发人员将如何在您的项目中导入您的记录器? 要添加功能或为Vapor创建第三方程序包,您需要创建一个“提供程序”。 提供者提供了一种在Vapor Web App中导入第三方程序包的统一方法。 […]
一生中至少有一个iOS开发人员至少从一个年轻的人或其他人那里继承了一个遗留项目,而当iOS开发成为独立开发人员的黄金竞赛时,其他人曾编写过代码。 那时,我们中只有少数人关心测试,可测试性,体系结构或模式。 只有大量的视图控制器,关心限制崩溃的数量,关心无限数量的功能和单例。 有很多单身人士。 Singleton非常容易用Swift中的1行代码和Objective C中的5行代码来实现,易于从应用程序中的任何地方调用,并且最好是弄乱代码以防止单元和UI测试。 本文的目的是为您提供一种有效且快速的工具,以解开任何单身汉,无论数量多少。 我将使用一个代码片段来给出我上面所描述的示例,并模拟3个单例服务和一个示例视图控制器。
*********本教程是使用Swift 3.0创建的******** Instagram具有很多魔力,并且作为当今最流行的应用程序之一,它提高了对其他应用程序的期望。 作为用户,我们常常忽略了出色应用程序的精妙之处,并且我们期望达到某种标准。 Instagram帖子上的缩放功能是这些标准之一。 本教程着重于复制该行为。 我是Rep的产品和工程负责人,Rep是一个有影响力的市场,品牌和有影响力的人可以在市场营销活动中进行协作。 我决定分享如何将此功能内置到用户个人资料中以放大照片。 我已经在下面附上了一些已完成结果的剪辑,但是为了详细介绍所有内容,我们将从头开始,并逐步解决它。 在项目设置中向左/向右移除风景,保留“纵向”选择。 好的,设置完成。 让我们开始编写我们的UI。 我喜欢以编程方式进行所有操作,但是如果您习惯IB,那么也可以这样做。 单击“ ViewController.swift”文件,然后添加表视图和数据源。 在创建带有要放大的图像的自定义单元之前,我们将使用UITableViewCell作为占位符。 现在是继承代码。 // ViewController.swift 导入UIKit 类ViewController:UIViewController { var tableView:UITableView! 覆盖func viewDidLoad(){ super.viewDidLoad() //加载视图后进行其他任何设置,通常是从笔尖进行。 view.backgroundColor = .orange setUpTableView() } func setUpTableView(){ tableView = UITableView() tableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableView) 让const:[NSLayoutConstraint] = [ tableView.topAnchor.constraint(equalTo:topLayoutGuide.bottomAnchor), tableView.leadingAnchor.constraint(equalTo:view.leadingAnchor), tableView.trailingAnchor.constraint(equalTo:view.trailingAnchor), tableView.bottomAnchor.constraint(等于:bottomLayoutGuide.topAnchor) ] NSLayoutConstraint.activate(const) tableView.register(UITableViewCell.self,forCellReuseIdentifier:“ cell”) tableView.dataSource =自我 […]
通过将2个或多个基本数据类型分组为单个复合数据类型来形成元组。 元组的每个元素可以是任何Swift基本数据类型。 元组中的每个元素之间的数据类型可以不同。 由于元组可以包含许多不同的类型,因此我们可以从任何类型的排列中创建元组。 元组不适合复杂和持久的数据结构。 对于复杂而持久的数据结构,我们应该使用结构或对象类。 要创建一个常量元组,我们使用相同的关键字let,然后使用关键字var来创建变量元组。 常量和变量的行为与Swift基本数据类型相同。 常量是不可变的,变量是可变的。 我们可以用字符串和整数组成一个元组,如下所示: 让contact =(“我的名字”,22341176) 要访问元组中的元素,我们使用从0开始的索引。 例: 0 接触1 像往常一样,我们也可以通过先声明一个元组来创建一个元组。 我们只需要将所有不同的数据类型放在方括号中即可,并用逗号将它们分开。 例: 让address1 :(字符串,字符串) address1.0 =“ A座公寓” address1.1 =“新泽西州” 地址1.0 地址1.1 请注意,尽管我们可以先声明常量而不分配数据。 这不是最佳实践。 为了声明常量,我们应该在同一条语句中声明并分配它们。 这是为了使我们的代码更安全。 我们只应声明元组,然后在绝对必要时分配数据。 对于变量,即使我们没有要输入的数据,也应首先声明和初始化变量。 创建元组变量的首选方法是使用以下方法同时创建和初始化变量。 var contact1 =(String(),Int()) contact1.0 contact1.1 contact1.0 =“这是一个测试” contact1.1 = 2132 contact1.0 contact1.1 contact1.0 =“大卫” contact1.1 = 76788779 contact1.0 contact1.1 对于元组中的每个元素,我们可以具有相同的数据类型。 […]
UITableView和UICollectionView是用于在任何类型的iOS应用程序中呈现数据的两个常见UI组件。但是将这些大数据呈现到单元中并不是什么大问题,主要的问题是我们如何处理这些数据。 让我们以UITableView为例,通常通过在viewController中采用UITableviewDatasource协议一致性,我们可以使用它的一些专用方法来处理tableview内部的数据呈现。 这是简单的代码片段示例 上面的例子非常简单,我们只是为viewController创建了一个扩展,并添加了所有tableview数据源方法。 它是如此的好和简单,但是为什么我应该使用Custom数据源呢? 好的 !!!! 当必须在其他视图控制器中显示这些相同的数据块时,您将怎么办。 没什么大不了的,我也将在其他视图控制器中创建相同的东西。 创建自定义可重用数据源可以处理整个应用程序中的所有数据源逻辑和数据模型渲染部分。我在整个应用程序中都说了。是的,但是不同控制器的数据模型不同,所以我将自定义数据源设置为一个通用模型类型,因此只需使用您的数据模型实例化此自定义数据源,以下是代码段。 在这里,我采用了模型(用于数据模型渲染),reuseIdentifier(用于使TableView单元格标识符出列)和CellConfigurator(它是一个元组,它同时容纳Data模型和UITableviewCell,其工作方式类似于tableview单元格中用于索引处行的闭包)作为参数以上课程。 我还在此类的扩展内部创建了一个静态方法来管理特定的数据模型。您还可以根据需要创建自己的模型。代码段。 扩展TableViewCustomDataSource,其中模型== ItemsDetailsLists {静态函数displayData(用于itemLists:[ItemsDetailsLists],withCellidentifier复用标识符:字符串)-> TableViewCustomDataSource {返回TableViewCustomDataSource(模型:itemLists,reuseIdentifier:reuseIdentifier,cellConfigurator:{(数据,单元格)入口itemcell: ItemListsTableViewCell =单元格为!ItemListsTableViewCellitemcell.setupParameters(itemlist:data)})}} 在您的viewController内部只需创建一个像这样的属性 私人var dataSource:TableViewCustomDataSource ? 这里的ItemDetailsLists是我的数据模型,一旦获得响应,就可以像这样设置您的customdatsouce属性,并将tableViewdataSouce设置为customdatasource。 func renderTableViewdataSource(_ itemlists:[ItemsDetailsLists]){dataSource = .displayData(用于:itemlists,带有Cellidentifier:“ ItemListsTableViewCell”)self.itemListTableview.dataSource = dataSourceself.itemListTableview.reloadData()} 这是完整的源代码Github链接 欲了解更多博客,请点击此链接 参考文献: *重构视图控制器,作者Paul Hudson Swift中可重用的数据源 通过约翰·桑德尔 Shakti Prakash在about.me 我是印度班加罗尔的软件工程师。 查看我的仓库。 关于我
1.在Swift中解释泛型? 利用GENICS,您可以编写可与任何类型一起使用的灵活,可重用的函数和类型 。 您可以编写避免重复的代码,并以清晰抽象的方式表达其意图。 Swift的Array和Dictionary类型都是通用集合。 在下面的代码中,用于交换两个值的泛型函数用于字符串和整数。 这是可重用代码的示例。 func swapTwoValues (_ a:inout T,_ b:inout T){ 让临时A = a a = b b =临时A } var num1 = 4 var num2 = 5 var str1 =“ a” var str2 =“ b” swapTwoValues(&num1,&num2) swapTwoValues(&str1,&str2) print(“ num1:”,num1) //输出:5 print(“ num2:”,num2) //输出:4 print(“ str1:”,str1) //输出:b print(“ str2:”,str2) //输出:a 2. swift中的可选内容是什么?何时使用可选内容? […]
回叫是一个非常有趣的话题,我们经常在Swift /目标C中遇到。在本文中,我们不仅会从理论上了解回叫,而且还将能够理解何时以及如何在代码中使用它们。 在开始之前,让我们先了解一下每次阅读回调时经常遇到的单词。 处理程序/完成处理程序 积木 代表们 关闭 以上所有术语表示同一事物,即“回调”。 它们只是在语法上有所不同。 块/闭包或委托具有不同的语法,但工作方式相同。 注意:我们将在稍后更加详细地了解Blocks,委托和闭包。 什么是回叫? 回调是一个函数或代码块,它将在某个时间点作为参数传递到另一个函数中。 func callback(){ // 做点什么 } func executeCallBack(回调){ //做点什么 } 现在的问题是,我们在哪里以及为什么需要回调。 假设要求我们构建一个应用程序以从服务器下载文件,并以下载百分比或下载完成后更新界面。 有了一个向服务器发出请求并下载文件的功能。 我们不能只是调用该函数并期望它在下载完成后返回,因为下载过程可能需要几分钟到几小时的时间,并且在那之前我们不能阻止UI。 在这种情况下,回调可以挽救。 我们可以使下载功能异步运行,尽管它会在下载完成之前立即运行,但是下载状态可以在实际完成后稍晚更新。因此,您要做的就是将下载功能传递给回调函数,以在下载完成后调用或更新进度百分比。 同样,让我们考虑另一种情况。 假设有一个要求,我们希望将数据从弹出窗口传递到呈现视图控制器。 请参考下图。 在这种情况下,还需要回调以将数据从弹出窗口传递到视图控制器,同时将其关闭。 简而言之,我们可以在以下情况下应用回调: 将数据传递到上一个视图控制器或更新UI。 当一个任务正在启动时,它将异步完成(即,将在调用函数返回后的一段时间内完成)。 让我们看一下带有多个回调(Swift 4.0)的以下示例: func downloadMethod(_ params:String, successHandler :@escaping(_ arg:String)-> Void, failureHandler :@escaping(_ error:Error?)-> Void) { //下载文件后成功回调 successHandler (“已成功下载。”) 如果让err =错误{ //如果发生某些错误,则调用失败回调 […]