Tag: Swift 4

UITableView中有多个UITableViewCells

本教程的重点是如何以尽可能少的代码正确地在UITableView中添加多个UITableViewCells。 在本教程中,我选择了一个场景,其中您的应用程序包含诸如联系我们,注册,登录等屏幕。简单地说,您需要在具有多种单元格类型的多个屏幕上显示表单。 当然,您可以将其应用于在UITableView中需要多个UITableViewCells的任何其他方案。 在开始之前,您需要了解几件事: 扩展名 枚举 关闭 自动版式 为了更好地理解,我创建了一个示例GitHub项目,您可以在此处下载。 创建UITableViewCells 首先,我们将从UITableViewCells创建开始。 如果打开项目,将在文件夹Cells下看到创建的各种单元格 ,这些单元格包含输入字段,下拉列表,操作按钮,多行输入字段。 出于演示目的,我将使用BaseCell和InputCell 。 我们将首先创建一个主单元(名为BaseCell),该单元将处理所有子级任务。 BaseCell用于存储所有子元素中相互共有的功能。 然后,我们将这些功能用作子单元格中的替代。 此单元格没有UI,但将从其子级中获取合适的UI。 基本单元 import UIKit class BaseCell: UITableViewCell { //MARK: Internal Properties var type: CellType! var pickerOptions: [String]!{ didSet{ pickerOptionsSet() } } var textChangedBlock: ((String) -> Void)? override func awakeFromNib() { super.awakeFromNib() // Initialization code } func setForm(title: […]

减少应用启动时间

你好,世界!!! 这是我的第一个故事。 我想分享一下我在优化应用启动时间方面的经验。 当我开始时,我想到的第一个问题是 App launch time 多少? 答案是,完成应用程序启动序列所花费的时间称为应用程序启动时间。 (我很确定,通过该链接并了解应用启动顺序将花费一些时间) 最简单的答案是,在您的代码(在application(_:didFinishLaunchingWithOptions:)内部application(_:didFinishLaunchingWithOptions:) )开始运行之前,启动应用程序所花费的时间称为应用程序的启动时间 下一个问题是,如何衡量应用程序的启动时间? 苹果公司已经考虑了这个问题,并保留让开发人员对其进行评估的条件。 它有两个步骤。 首先是: 切换到释放模式(参见图1)。 您需要添加名称为DYLD_PRINT_STATISTICS且值为1环境变量(请参DYLD_PRINT_STATISTICS 2)。 现在,启动应用程序时,您可以在控制台部分的顶部看到日志。 有两种启动方式。 冷启动和热启动。 通常,冷 启动更重要。 衡量冷启动更重要的原因是用户重启手机后启动应用程序,或者很长时间以来第一次启动应用程序,这才是您真正希望它能立即启动的原因。 热启动是一种应用程序,其中的应用程序已经在内存中,这是因为它已经被启动并已退出,并且仍然位于内核中 因此,当我检查冷启动时,观察到以下内容: 主时间总计:675.22毫秒 dylib加载时间:535.96毫秒 重新设置/绑定时间:50.58毫秒 ObjC建立时间:35.27毫秒 其他初始化:X毫秒 苹果表示,应用程序启动时间应在400毫秒左右。 显然,这超出了预期。 我们可以看到加载dylib占用了最大的部分。 这是加载依赖关系所花费的时间,我现在可以在我的项目中看到30个pod和依赖关系。 问题是如何减少此dylib的加载时间? 第一步是避免使用库,但是随着开发的进行,库的数量开始增加。 因此,采用预防性方法,请尝试使用具有快速代码的库(考虑到您的项目处于快速状态)。 其次,对于所有库,请进行构建设置>> Mach-O Type并将其值设置为static library (请参见图3)。 当您将其设置为static library 文件在构建时链接。 代码被复制到可执行文件中。 程序中未引用的库中的代码将被删除。 仅具有静态库的程序在运行时没有任何依赖性。 这是更改后我的应用程序的日志: 主时间总计:430.53毫秒 dylib加载时间:333.09毫秒 重新设置/绑定时间:26.39毫秒 ObjC建立时间:20.72毫秒 […]

警报控制器的最佳实践🚨

嘿! 让我们美化警报控制器🤓。 我们将创建警报控制器,并尝试尽可能地对其进行清理。 让我们潜入 当我需要在我的应用程序中使用警报时 ,我便开始像以前一样创建警报 。 您可能对此很熟悉。 可以,但是如果您的应用需要多个警报,该怎么办? 🧐 答:复制并粘贴,更改字符串即可。感谢您再见👋🏻 是的,它将起作用work 但是,如果您的应用程序需要多个警报和DRY(请勿重复自己)代码,该怎么办? 嗯? 然后世界变了🙃 我们可以从创建一个函数开始,让我们尝试 现在,您可以在需要调用该警报时调用myAlertVC()方法,但是这里的问题是您无法更改将显示与myAlertVC()调用的警报相同的警报的字符串。 让我们向myAlertVC()函数添加一些功能,以便我们可以更改字符串。 这就是您如何调用此方法myAlertVC(title: “Hello!”, message: “Wazzup?”, actionTitle: “OK”) 真好! 每当需要显示新警报时,都可以调用此方法。 但是仍然不是最好的选择。 你只能叫它 在当前的ViewController上。 对于其他UIViewController子类,我们需要创建新函数,如上面的函数。 别忘了你不应该重复自己 因此,我们还需要诸如全局函数之类的东西,以便我们可以在任何UIViewController子类上调用它。 让我们尝试为警报创建一个新类 我们on vc: UIViewController参数on vc: UIViewController添加on vc: UIViewController参数,因为我们需要在调用此方法的视图控制器上显示它。 现在,您可以转到视图控制器并创建MyAlertController的实例 let myAlertController = MyAlertController() 现在您可以调用myAlertController的方法 好的,我们现在出发了,我们有警报控制器的特殊类。 同一类more上不再有代码垃圾。 让我们看看是否可以进一步删除一些代码并清理视图控制器。 我们可以删除字符串并在MyAlertController类上为每个警报创建函数 现在,您可以在我们的视图控制器上调用showErrorMessage(…)函数。 myAlertController.showErrorMessage(on: self) 凉! 从现在开始,您可以在任何UIViewController子类use上使用它。 […]

在Swift 4.2中验证textField输入的通用方法

为了创建通用验证类,我将使用可变参数,元组,正则表达式和枚举。 枚举是迅速开发人员的强大工具。 我们将从Alert,Valid,ValidationType,RegEx,AlertMessages的枚举开始。 现在,最后我们将做最后一个枚举,以返回验证失败消息。 现在,我们完成了使用枚举设置所有自定义参数类型的操作。 比赛结束了一半。 成为NFS Player,开始建立共享类进行验证,以加速完成比赛。 现在,我们完成了您的通用验证文件。 享受快乐编码🙂 仅需一秒钟,就可以通过两个示例快速了解如何使用此验证类。 拍手,如果您喜欢这篇文章并关注我… Github回购链接:-https://github.com/SandeepSpider811/ValidationExampleSwift 您可能感兴趣的其他文章: #iOS中的3D Toch Peek和Pop #动态的附件视图高度 #验证UITextField响应者的通用方法 #使用.xcconfig文件在Xcode Project中存储各种SDK密钥和ID。 #Xcode中的颜色资产(.xcassets)。

Swift并行编程—第2/4部分

目标队列,调度组,屏障,工作项,信号量和调度源 本文是Swift并行编程的第2部分。 与第1部分一样,我们研究了Dispatch Queue和系统提供的队列。 在本文中,我将重点介绍另一种定义任务和GCD提供的强大API的方法。 如果要查看系列的所有部分: 并发和GCD — Swift并行编程— 1/4 GCD —使用Swift进行并行编程—第2/4部分 议程: 目标队列 调度组 DispatchWorkItem 派遣壁垒 DispatchSemaphore 派遣源 1.目标队列 定制调度队列不执行任何工作,它只是将工作传递给目标队列。 默认情况下,自定义调度队列的目标队列是默认优先级的全局队列。 从Swift 3开始,一旦调度队列被激活,就无法再对其进行更改。 可以通过setTarget(queue:)函数设置自定义队列的目标队列。 在激活的队列上设置目标将进行编译,但随后会在运行时引发错误。 幸运的是,DispatchQueue初始化程序接受其他参数。 如果出于某种原因仍然需要将目标设置在已创建的队列上,则可以使用iOS 10以来可用的initiallyInactive属性来实现。 DispatchQueue(标签:“队列”,属性:.initiallyInactive) 这将允许您修改它,直到激活它。 DispatchQueue类的activate()方法将使任务执行。 由于队列尚未被标记为并发队列,因此它们将以串行顺序运行。 为了使队列并发,我们需要指定: DispatchQueue(标签:“队列”,属性:[。initiallyInactive,.concurrent]) 您可以将任何其他调度队列(甚至是另一个自定义队列)传递给目标队列,只要您从未创建周期即可。 通过简单地将自定义队列的目标队列设置为其他全局队列,可以使用该功能设置自定义队列的优先级。 只有全局并发队列和主队列才能执行块。 所有其他队列必须(最终)以这些特殊队列之一为目标。 您可能已经在使用的Dispatch API或框架中注意到了目标队列。 我在RxSwift库中发现了目标队列的使用。 使用此实现,由于任务正在异步执行,因此很难在完成时获得通知。 这是DispatchGroup图片: DispatchGroup允许工作的聚合同步。 它可以用于提交多个不同的工作项或块,并跟踪它们何时全部完成,即使它们可能在不同的队列中运行。 唯一必要的事情是在调度组上均衡地调用enter()和leave() ,以使其同步我们的任务。 调用enter()以手动通知组任务已开始,并leave以通知工作已完成。 您也可以调用group.wait() ,它会阻塞当前线程,直到该组的任务完成为止。有两种方法来调用完成块: 使用wait()然后在主队列上执行完成块 呼叫组notify() wait(timeout:) 这将阻止当前线程,但是在指定的超时后,无论如何仍将继续。 […]

CoreData基础知识(Xcode 9 + Swift 4)

在那篇文章中,我将向您展示CoreData框架的一些基础知识,该框架是用于iOS,macOS,tvOS和watchOS平台的工具,用于管理对象建模 , 生命周期和持久性 。 但是,我不会尝试总结或涵盖文档中的每个要点。 您可以在这里自己做— https://developer.apple.com/documentation/coredata。 相反,我将向您展示如何对对象建模以及如果要读取或写入某些东西如何运行查询 。 我们将创建的示例项目将使用Xcode 9和Swift 4构建。 让我们弄脏双手吧! 首先,让我们创建一个新项目,然后选择“ Use Core Data” 。 尽管您可以为现有项目添加该框架,但是从该位置添加框架会更容易,因为一切都已经为您完成。 创建项目后,您将看到添加了CoreDataTest.xcdatamodeld之类的文件。 单击它时,您将看到一个工具,可用于配置代表数据模型的实体。 您可以为每个实体定义一些事物,但对我们而言, 属性和关系将是最重要的。 让我们添加一个名为User的新实体(单击“ 添加实体”按钮以更改其名称,在顶部两次单击新添加的实体的名称,然后键入您的名称)。 现在,让我们添加一些属性来定义新实体的架构: email —字符串, 名称 —字符串, date_of_birth —日期, number_of_children —整数16 同样,让我们​​添加一个名为Car的新实体,该实体将包含属性: model-字符串, 年份 -整数16。但是现在让我们在car和用户之间添加关系。 为此,我们将从该点向User实体添加一个由user表示的关系。 比起您必须回到User实体并设置与Car的关系。 之后,您可以在Car上设置与User的逆关系。

ISP:接口隔离原理

根据方法组将Fat协议转换为小型协议 接口隔离原则( ISP)指出: 不应强迫客户依赖他们不使用的方法。 在设计应用程序时,我们应该关注包含多个子模块的模块抽象。 在创建另一个仅包含原始系统子模块的模块时,我们被迫实施完整协议并编写一些虚拟方法。 这样的协议被称为胖协议。 ISP帮助我们避免: 胖接口 不要强迫类实现他们无法实现的方法 不要用很多方法污染协议 接口隔离原则主张将“胖接口”隔离为较小的且高度紧密的协议,称为“角色协议”。 每个“角色协议”都声明一种或多种用于特定行为的方法。 因此,客户端只能实施与其方法相关的那些“角色协议”。 违反接口隔离原则: 当客户端依赖于不使用的方法时,这意味着抽象是错误的。 如果ImageMessageView和VideoMessageView实现此协议,则由于图像视图不了解视频播放器,反之亦然,因此将产生开销,因此需要实现虚拟方法来满足编译时错误。 使协议方法为可选的另一种解决方案是在协议扩展中创建虚拟方法,然后覆盖特定类中的必需方法。 遵循接口隔离原则: 通过遵循ISP,我们可以将上述协议分为2部分: 现在, VideoMessageView可以只符合DeepLinkVideoMessage 。 将来如果需要删除视频消息,我们可以简单地删除此协议并查看而无需触及其他代码。 与ImageMessageView相同

在Swift 4中构建计算器

使用NSExpression构建计算器。 Swift语言从不让我惊讶于它提供的所有功能。 我给自己做了一个构建简单计算器作为编码组件的任务。 我已经用Java构建了一个计算器,并且我想起了执行所有数学逻辑的“ if”和“ case”语句数量之多。 因此,我开始构建了自己的布局,如上面的屏幕所示。 我使用Snapkit布局视图。 这篇文章不会涵盖Snapkit,但您可以将其作为Snapkit的介绍来阅读 。 因此,我们将不使用“ if”或“ case”语句来执行所有计算。 您可能想知道怎么做? 我的意思是Swift将如何知道何时添加或减去或执行任何其他数学函数? 在Swift, NSExpression中进行数学运算时欢迎您的朋友! 谁和什么是NSExpression ? 用于比较谓词的表达式。 NSPredicate中的比较操作基于两个表达式,由NSExpression类的实例表示。 为常量值,键路径等创建表达式。 这就是Swift文档中的定义。 没有告诉我们太多。 可以很容易地看到NSExpression的运行状况 ,以便更好地了解其功能。 let mathExpression = NSExpression(format: “16 + 30”) let mathValue = mathExpression.expressionValueWithObject(nil, context: nil) as ? Int 是的,这就是进行数学😱👏🏾🎉所需的全部代码。 NSExpression的计算方式比简单的数学方程式还多。 此处的这篇帖子通过NSExpression及其可以为您提供的功能进一步深入。 因此,在上面的一个功能中,我能够为我的计算器执行所有必要的数学计算。 正是由于这样,我才建立了一个功能齐全的计算器。 最终计算器具有许多其他功能,例如用户操作的历史记录以及能够返回到先前操作的功能。 您可以在我的Github页面上查看完整的实现。 妈妈,没有情节提要! 作为一名自学成才的iOS开发人员,他通过使用以下方法观看Youtube教程和在线课程来学习大多数技能: medium.com

Swift:使用NumberFormatter在Integer上添加分隔符

如果要将整数值分成由字符(即1.000、1 000 000)分隔的组,则需要使用NumberFormatter 。 什么是NumberFormatter? NumberFormatter是在数字值及其文本表示形式之间转换的格式化程序。 如何使用它 为了方便使用,我们将创建两个扩展文件,使我们能够在项目中全局使用它。 Formatter + Extensions.swift extension Formatter { static let withSeparator: NumberFormatter = { let formatter = NumberFormatter() formatter.groupingSeparator = ” ” formatter.numberStyle = .decimal return formatter }() } 使用groupingSeparator可以确定分隔符是什么。 在这种情况下,它是空格,但是您可以添加任何其他特殊字符(例如点或逗号)以使其为1.000或1,000。 Int + Extensions.swift extension Integer{ var formattedWithSeparator: String { return Formatter.withSeparator.string(for: self) ?? “” } } 接下来,我们将从上述扩展中调用静态变量withSeparator ,并创建一个名为formatterWithSeparator的新变量。 […]

Swift第一部分的闭包

如何创建没有名字的功能! 介绍: 闭包是swift最有用的未来之一。在这三部分的文章中,我将以现实生活中的例子从最基本的方面来解释闭包。 什么是闭包: 闭包只不过是没有名字的函数。它意味着闭包是一个没有名字的函数,用不同的语言来调用,就像:匿名函数,回调,lambdas等。 换句话说,闭包是自我包含的功能块,可以在代码中传递和使用。 在深入探讨闭包之前,我们先创建一个函数并将其转换为闭包。这使我们的概念更加清晰。 简单功能: 如果我们考虑功能和闭包,那么我们可以像这张图那样说明闭包和功能。 让我们讨论闭包语法。 基本语法: 关闭以大括号开头,以大括号结束。这是简单的关闭语法: {{argumentName:Type)-> ReturnTypein //声明和其他 // …… // ….. 返回} 这是闭包的基本语法,以大括号开头,而不是参数名称及其类型,比返回类型比关键字中的语句要大,并且比return还要大。 范例一: 闭包的另一个基本示例,参数取两个值并进行计算并将其返回。如果执行此闭包,则可以执行以下操作。 let result = clasureOne(10,50)//结果应为500 示例二: 该闭包采用两个字符串,并将其作为单个字符串返回给字符串。顺便说一句,此闭包也分配给closureTWo变量。 var fullName = closureTWo(“ Mahmudul”,“ Hasan”) // fullName变量现在获得了“ Mahmudul Hasan” 以不同方式创建: 我们知道Swift是一种类型 – 安全的语言,因此在函数或闭包中,我们需要定义每个变量或常量的类型,然后隐式或显式初始化它。对于此功能,我们可以通过多种方式创建闭包Let Start .. 这个addTwoNumber闭包我们在equal =之前定义类型,并从闭包头中删除类型,这样我们可以这样写。 我们可以省略标题的返回类型,也可以变得足够聪明以至于无法理解 现在我们也可以从主体中删除return关键字。 现在我们可以像这样写在一行 现在非常简写,而且非常简短 因此这里是一个有趣的swift闭包,了解它有两个变量并将其添加并返回变量addTwoNumber 。因为我们明确定义了它的类型。而swift的默认参数名称为$ 0,$ 1,$ […]