在上一篇文章中,我谈到了结构,因此我只认为对Classs进行跟进是正确的。 将Classes制造商用来生产产品的模具。 您可以基于一个模具来创建许多产品。 使用一个模具( class ),您可以基于每个模具具有的形状,大小等属性( properties )来创建多个产品( objects )。 让我们看一下代码 打开操场跟进。 这是class的基本语法。 如果您熟悉结构,您会注意到类似的类语法。 假设我们有一个简单的Person class示例。 在该类中,我们将具有name和age的properties ,然后将其赋予一个initializer 。 initializer是我们每次尝试创建Person object时都会运行的方法。 在初始化程序中,我们传递组成Person的参数。 我们简单地创建一个名为person1的变量,该变量等于Person class ,当添加括号时,它将询问我们在初始化器中声明的参数。 现在我们可以使用person1对象并获取其属性。 类中的功能 我们还可以在类中使用函数,这将使我们的人员对象具有调用能力。 使用getName()我们返回一个String说“您的名字是_____” 我们可以通过person1对象访问函数。 类是引用类型 类是引用类型,而结构是值类型。 我将演示引用类型如何工作。 如果您想了解结构和值类型,请转到我的前一篇文章。 如果要创建一个新对象, person2如下所示: 然后创建一个变量person3 等于 person2 : 然后我们更改person3的属性,让我们看看它将如何更改person2。 让我们给person3 55岁 。 现在,让我们同时阅读person2和person3的年龄。 您可以看到两个年龄都相同。 为什么? 这是因为person3本质上是person2。 当我们存储一个类时,我们会将这些信息存储在内存中,并且person2持有对该数据所在位置的引用。 当使person3等于person2时,我们只需查看该数据的相同参考位置。 Person3不是person2的副本。 是人2。 希望有道理。 包起来 这是有关类的非常准系统的文章,我计划在另一篇文章中也涉及类的继承。 […]
自从我在Envelope框架上发表我的上一篇文章以来已经有一段时间了-Alamofire周围的薄包装使编写网络代码的单元测试变得轻而易举。 可能一开始这篇文章太大了,但是无论如何我都希望听到更多的反馈。今天,我将分享我几年前一直在使用的一个非常简单的技巧,该技巧简化了另一个方面编写单元测试的方法:测试使用当前日期/时间的代码。 问题 因此,想象一下您正在编写一种方法,如果记录已过期,则请求更新记录: 在这里, entityManager是一个对象,负责通过id请求和存储对记录的更新。 如何对这种功能进行单元测试? 看到问题了吗? 我们需要一个nonExpiredRecord ,即条件为record.lastUpdateTime <= dateOfExpiration为false的Record实例。 因此, RecordFixture.nonExpiredRecord()应该生成一个带有lastUpdateTime更新为当前时间的记录! 想象一下,当Record是一个struct时,会是什么样子–您将必须复制该结构的所有字段,并用当前日期更新一个字段。 甚至更糟的是,当这样的设备来自例如保存的网络响应时,其模式可能会随着时间而变化,支持这样的测试代码变得很痛苦,并且是CI失败的根源。 即使夹具的结构正确,但如果经过了实际时间,在调试器中单步执行功能也可能导致将条件评估为错误的结果。 解决方案 冻结时间。 /明显的模式开启/单元测试应该是确定性的。 甚至那些处理当前时间的事件。 /关闭明显的模式/ 想象一下,在单元测试套件下运行时调用Date()总是会返回,例如, 1 January 2016 12:00GMT ? 然后为总是“未过期”的记录创建测试夹具将是微不足道的,不是吗? 那么,如何在单元测试中覆盖Date() ,使其返回预定义的日期呢? 不管是好是坏,这是不可能直接实现的—复杂的方法实现现在已经成为过去。 我们可以做的是: 提供Date()的替代方法,该替代方法将在正常程序执行下返回当前日期,并具有单元测试套件覆盖其行为的能力; 在测试套件中,将其覆盖以始终返回预定义的日期; 禁止使用lint规则或git pre-commit钩子,或同时使用这两种方法在源代码中使用Date()初始值设定项。 让我们一步一步地做。 1.提供获取当前日期的替代方法。 2.覆盖测试套件下的当前日期行为。 如果未使用Quick ,则可以通过重写单元测试套件类的class func load()函数来完成相同的操作。 因此,现在,在测试套件中运行时,主应用程序模块中调用Date.current的代码将始终返回Date.mockDate的值,因此测试治具现在可以是常量(例如,从保存的JSON加载),也可以构造使用已知的模拟日期: 3.禁止在代码中使用Date() 。 让我们在git pre-commit钩子脚本中添加一个部分,并使用简单的regexp查找所有出现在舞台区域的Date()模式的出现: 骇客入侵!
自动布局使用约束的优先级来解决两个不同约束之间的冲突。 对于具有固有大小的视图,自动布局使用内容拥抱和内容压缩抵抗来解决冲突。 让我们考虑一个例子。 假设我们有一个固定的高度视图,其中有两个标签作为子视图,如下所示。 它可以是标题和内容标签。 标签具有固定的顶部和底部间距,并具有最高优先级。 观察下图,标签内容恰好适合可用空间。 标签的内在内容大小等于可用空间。 内容拥抱 让我们考虑另一个例子。 两个标签都有一行内容。 现在,标签必须超出其固有大小,才能满足标签的约束并适合视图内部。 自动布局是一个冲突。 它必须展开其中一个标签,但无法确定。 因此,它使用内容包含优先级来解决冲突并扩展其中之一。 我为第一个标签指定了最高的内容优先级,以防止其增长。 具有最低优先级的第二个标签会超出其固有内容大小,以容纳剩余空间。 内容拥抱优先级可以设置如下 titleLabel.setContentHuggingPriority(.defaultHigh,for:.vertical) subTitleLabel.setContentHuggingPriority(.defaultLow,for:.vertical) 也可以在情节提要中设置 耐含量压缩 考虑另一个示例,其中两个标签的内容都较大。 现在两个标签都无法在可用空间中显示完整的内容,它不得不缩小其中一个标签,但无法确定它。 自动布局是一个冲突。 因此,它使用内容压缩抵抗来解决冲突并缩小其中之一。 如果需要,我希望标题标签显示完整的文本,而内容标签缩小。 为标题标签设置更高的抗压缩性可防止其收缩。 耐内容压缩性可以如下设置 titleLabel.setContentCompressionResistancePriority(.defaultHigh,for:.vertical) subTitleLabel.setContentCompressionResistancePriority(.defaultLow,for:.vertical) 也可以在情节提要中设置它 今天就这些。 通过https://twitter.com/ideekshi与我联系
允许用户筛选您的列表可以改善用户的整体体验。 在这里,我们将学习如何使用现有的表格视图配置UISearchController并应用搜索栏。 因此,让我们直接进入。 入门项目 让我们从以下针对iOS 8及更高版本的入门项目开始。 我在以前的文章中没有使用过Storyboard,所以我决定在这里使用它。 如果您现在运行该应用程序,将会看到一个宠物小精灵的列表,其中包含它们的名称,元素和图像。 我们将要交互的主要文件如下 Pokemon.swift —包含宠物小精灵的名称,元素和图像的模型类 PokemonDataSource.swift —包含用于生成口袋妖怪列表的类方法 ViewController.swift —显示宠物小精灵的列表 配置SearchController 在ViewController.swift中,让我们添加到我们的searchController中。 注意,我们为参数传递了nil。 如果要在显示可搜索内容的同一视图控制器中显示搜索结果,请指定nil。 私人让searchController = UISearchController(searchResultsController:nil) 现在,我们有一个要管理的UISearchController实例,让我们继续进行配置。 在函数configureSearchController()中,添加以下内容 searchController.dimsBackgroundDuringPresentation = false definePresentationContext = true tableView.tableHeaderView = searchController.searchBar 通过将dimsBackgroundDuringPresentation设置为false,我们可以通知searchController在激活背景时不要使其背景变暗。 您应该将其设置为yes只是为了第一手看到它。 注意,我们将definePresentationContext设置为true。 这样可以确保,如果我们导航到另一个视图控制器,则搜索栏应仅保留在原始视图控制器中。 您应该看到以下内容; 但是,您会注意到搜索当前无效。 因此,让我们添加此功能! 文字过滤器 我们首先需要遵守UISearchResultsUpdating协议,以利用方法updateSearchResultsForSearchController(:) 每当搜索栏成为第一响应者或对搜索栏中的文本进行更改时,都会自动调用此方法。 在此方法内部执行所有必需的筛选和更新。 现在,我们将扩展ViewController使其符合UISearchResultsUpdating。 在这里,我们将实现此方法并将其调用filterSearchController(:)。 我们将在短期内重用filterSearchController。 func updateSearchResultsForSearchController(searchController:UISearchController) { filterSearchController(searchController.searchBar) } 由于我们将显示已过滤的宠物小精灵的列表,因此我们不想破坏我们的pokemonList数组。 为了保留我们原来的pokemonList,我们将一个filteredPokemonList变量添加到我们的ViewController中。 注意它是可变的,因为它将经常更改。 […]
几乎每个认真进行iOS开发的人都经历了为一个人处理约束的痛苦,这对于大多数人和两个人来说似乎都是不可思议的,您永远无法真正摆脱它们的需求。 我们需要告诉OS将UI元素放置在屏幕上的位置。 这考虑了对内部变化(如动态内容)或外部变化(如形状因数,屏幕方向和旋转)的响应。 根据官方文档,有三种方法可以执行此操作: 布局用户界面的主要方法有三种。 您可以以编程方式对用户界面进行布局,可以使用自动调整大小的蒙版来自动化对外部更改的某些响应,或者可以使用“ 自动布局” 。 在这三者中,我们将讨论“自动布局”。 自动布局是在iOS 6中引入的,它是一个系统,可让我们通过创建元素之间关系的数学描述来布局用户界面。 我们根据对单个元素或元素集之间的约束来定义这些关系。 如果我们的用户界面是建筑物,则将约束视为将所有东西都放在定义的位置的脚手架。 通过自动布局使事情进展最快的方法是堆栈,固定,对齐和解析工具。 堆栈是使用自动布局而不使用约束的工具。 这就像选择各种元素并将它们放到堆栈中一样容易,因此在屏幕旋转时,它将保持内部元素之间的对齐。 堆栈视图可能是最快且无混乱的UI布局方式,但是请记住,它们是iOS 9中引入的,因此不能用于以前的版本。 好吧,裸体谈话! 让这些手变脏,在自动布局中通过引脚对齐和固定。 假设您有一个UI要求,即在potrait模式下必须有两个等号的按钮在一个按钮的下方显示,而在横向模式下,它们应彼此并排显示。 而且,我们将完成所有这些工作,而无需触及任何一行代码,保证! 我们将学习如何通过尺寸类来做到这一点。 这是一个非常酷的3×3矩阵,可以说是构建UI的最快,最有效的方法。 wAny hAny表示所有方向上的所有形状因子。 这也意味着我们在其中设置的任何元素或约束在所有设备和所有方向上都是可见的。 您的应用程序可能同时处理iPad和iPhone,因此最好放置UI中常见的元素。 当设计要求发生变化时,这可以帮助您节省时间并易于使用。 转到视图并将按钮放入其中,将它们分别命名为绿色和红色,并更改其背景颜色。 我们将从设置绿色在屏幕上的位置开始。 这将是风景和肖像之间的唯一共同约束。 按下“固定”工具,然后取消选中“到边距的约束”复选框,然后固定2个边缘(前导和顶部),如下图所示: 我们将更改Size类,因为我们希望iPhone处于纵向模式,我们将鼠标悬停在矩阵上,并将宽度Compact和height设置为Any(3×1),它将覆盖纵向模式下的所有iPhone。 接下来,如图所示,将后缘以50px固定在绿色上: 自动布局附带三个方程式,它们定义了绿色按钮与父视图的关系。 在这一点上,必须了解自动布局如何看到这些约束,等号表示项目在左侧和右侧的相等性,而不是赋值。 自动布局会努力使=符号两侧的两个实体相等,同时这样做肯定会有错误,请参阅官方文档,以了解它引发的各种错误及其原因。 现在我们已经设置了绿色按钮的位置,我们要做的就是使红色按钮完全相同,并将其放置在比绿色按钮低20px的位置。 在继续之前,请从“解决”菜单中执行更新框架。 现在,我们将使用“对齐”工具,同时选择两个按钮,然后检查“前缘”和“后缘”按钮。 自动布局足够聪明,可以解密哪个按钮的边缘与谁对齐。 更新框架,您会在绿色的顶部看到红色,并且高度和宽度相等,但是自动布局仍然会抱怨您尚未将红色绑定到Y轴。 将红色拖动到绿色下面,不用担心您不需要准确,我们可以自动布局! 完成后,将红色顶部固定为20px。 切记取消选中“边距约束”。 另外请记住,我们需要绿色按钮中的20px,下拉菜单将为您提供您要固定其位置的选项,请选择绿色。 添加约束并更新框架。 瞧! 您已经创建了无冲突的用户界面!! 在我们高兴之前,这项工作尚未完成。 我们必须在横向模式下并排显示按钮。 在文档概述中完成此操作后,您将注意到一些约束方程式变为灰色。 这是因为,我们告诉自动布局如何在iPhone纵向模式下而不是横向模式下将这些按钮保持在原位,这就是我们现在要完成的工作。 跳至文档大纲,然后选择红色和绿色。 […]
(由我们自己的Mobster Sameh Mabrouk ,高级iOS开发人员 @Mobiquity贡献 ) 代码审查的定义: 根据维基百科: 代码审查是计算机源代码的系统检查(有时称为同行审查)。 它旨在发现在初始开发阶段被忽略的错误,从而提高软件的整体质量。 好吧,我想这样做! 等等,但是…… 怎么做? 可以采用多种形式进行审核,例如配对编程,非正式演练和正式检查。 最有名的大概就是这个-给我看看您的代码(又名非正式评论)! 只需让您的同伴查看您的代码即可。 可以使用不同的工具(例如Atlassian的Crucible / Fisheye或BitBucket / GitHub上的拉取请求)或任何您使用的工具来执行正式代码审查。 借助这些工具,您可以很好地看到对源代码所做的更改,可以对它们进行注释,向作者提出一些问题,然后他们可以解释其代码。 就像您在现实生活中进行的对话一样,但是要记录在案–同意的内容应该在合并成开发之前执行。 等待,什么合并? 我们只是在谈论评论… Git流 在工作中开发应用程序的不同部分时,我们使用Git和Git Flow将所有更改合并到父分支中。 应用功能完成后,我们将创建一个请求请求,其中包含要添加到先前分支(通常是开发 )中的更改。 我认为,显示流程的最佳图片来自GitHub。 流程如下所示: 从开发创建分支 将您的更改应用于源代码 创建一个合并到例如开发中的拉取请求 与同事讨论变更,解释您的观点并应用建议的改进措施 您的同伴批准您的更改 将您的代码合并到源分支 进行审核时应该注意什么? 您绝对应该检查代码的完整性-样式是否与以前的解决方案匹配,是否遵循约定的约定? 功能是否正确实现(关于这一点,我会建议PR创建者是否可以添加.GIF图像来说明功能的工作原理,这样很好) ,更改后旧的源代码是否可以正常工作? 为什么要在开发过程中关心代码审查? 可以肯定的是,由于它确保代码完整性(),因此可以捕捉到其他人看不到的东西。 它可以让您学习和分享您的知识和专长,通过与您共同的话题(代码和编程技能;)的对话,加强团队中的沟通并建立良好的关系;)! 就我个人而言,最近在我当前的项目中已经看到了。 团队在沟通方面存在问题,但是在我们进行了代码审查的对话之后,沟通变得更好了。 将代码审查视为对未来的投资。 如果您现在不捕获错误,那么将来一定要征服它们。 如果您不执行代码审查该怎么办 想象一家X公司,它为多个客户提供移动应用解决方案。 他们的团队很小,有时甚至无法满足客户的需求。 因此,他们决定将一些工作外包给外部公司。 他们向该公司提出项目要求,并在3个月后再次开会以接收应用程序源代码。 但是该应用程序无用,它在网络调用时冻结, […]
所以……设计团队只是要求您使动画更性感,然后您变得苍白。 他们是什么意思? 当他们开始谈论关键帧和动画曲线时,情况变得更加尴尬。 动态图形应用程序提供了很大的灵活性,并且对于设计人员而言,有时可能期望在Swift / Cocoa Touch中可以找到相同的灵活性。 当然,我们都知道Swift很棒,一切皆有可能,但让我们坚持基础。 对于UIView动画,我们可以找到以下曲线预设: 枚举UIViewAnimationCurve:Int { 案例EaseInOut 案件缓入 案例缓出 线性情况 } 要尝试这些方法,我将对带有圆角的UIView应用简单的比例转换。 当设计师要求您使动画更性感时,这不是他们的意思。 😉线性曲线是最简单的曲线。 对于我们的比例动画,它使它突然结束。 缓入 缓入会在开始时弯曲曲线。 应用它时,我们的视图在开始时缩放较慢,因此在结束时缩放较快。 这条曲线在这里不太理想。 由于比例尺从0.0开始,因此早期的转换会以看不见的子像素出现。 几乎就像动画只是延迟了开始一样。 缓出 现在,我们不是在开始时放慢速度,而是在年底时放慢速度。 这对于我们的动画效果更好。 缓入缓出 组合“ 缓入”和“ 缓出”时 ,我们得到一条S形曲线,这会在开始和结束时减慢动画的速度。 由于这是UIView动画的默认曲线,因此我们现在可以将代码重构为: 哇! 我们的曲线迅速脱离图表,并在其稳定下来之前将视图缩放到100%以上。 让我们通过将阻尼比增加到0.7来减少弹簧振荡。 更好。 现在,您当然可以说动画蓝色圆圈永远不会令设计师满意,因此让我们看一个更高级的动画。 在这里,我使用了多个春季动画。 它们中的每一个具有0.8秒的持续时间和0.4的阻尼比。 现在,这是一个性感的动画,而我们的春季动画给设计团队留下了深刻的印象。 任务完成! 在我的下一篇文章中,我将进行更深入的介绍,并解释什么是关键帧以及它们如何与UIView动画一起使用。
本篇文章将按步骤详细说明,如何在iOS TableView中实作Parallax的其中一个视觉效果,Demo Project使用XCode 8,Swift 3 ,适合读者为: 了解ScrollView的ContentOffset属性以及委托设计Patten。 熟悉ImageView的ContentMode属性。 对AutoLayout有基本了解。 下图为想要实现的效果,上方的ImageView会跟着拖动的动作产生相对应的变化。 步骤1:从 Dropbox 下载启动项目 。 (按此下载) 下载后,打开ParallaxDemo.xcodeproj ,里面已经有一个写好的TableView,在每一个单元格里面显示每一个各自的行号。 步骤2:透过TableView的ContentInset属性,将TableView往下移,腾出上方的空间,给后续要置入的ImageView使用。 在DemoTableViewController里添加一个imageViewLength属性: 类DemoTableViewController:UIViewController,UITableViewDelegate,UITableViewDataSource { // 1 让imageViewHeight:CGFloat = 200.0 … } 在DemoTableViewController里面的setUpTableView()函数中加入以下代码: func setUpTableView(){ // 2 tableView.contentInset = UIEdgeInsets(顶部:imageViewHeight,左侧:0,底部:0,右侧:0) // 3 tableView.contentOffset = CGPoint(x:0,y:-imageViewHeight) … } 以下说明每一段程式码的作用: 设定要留给ImageView的高度,将之存在ImageViewHeight属性中,以供后续使用。 设定TableView的ContentInset,这个属性的资料类型状态是UIEdgeInsets,透过分别设定上,左,下,右,可以调整TableView的内容视图与底下ScrollView的相对距离。这里我们把ImageViewHeight作为UIEdgeInset初始值设定项的top参数,并将这个新生成的UIEdgeInset物件指定给TableView的ContentInset属性。 设置好ContentInset后,为了让一进来App的时候,显示上方的空白,我们还必须设置TableView的ContentOffset,让上方的空白可以被看见。 设定完这些指令之后,跑模拟器就可以看到下方的画面: 步骤3:添加ImageView 在DemoTableViewController里添加setUpImageView函数: 接下来就进到更重要的部分,UIScrollView有相对应的协议:UIScrollViewProtocol,会在发生一些事件的时候通知委派对象,执行相对应的方法,而UITableViewDelegate协议继承自UIScrollViewDelegate,自然也继承了这些方法。我们将会用到scrollViewDidScroll()这个功能。 将下列的程式码新增到DemoTableViewController中: 3. changeImageViewHeightConstraint(contentOffset:CGPoint) 当TableView已经被滑到最上层的画面,还继续被拖动的时候,我们希望imageView变大,来替换空白,所以我们去修改的imageViewHeightConstraint,让imageView随着拖动的动作高度变大,而因为contentMode设置为ScaleAspectFill的关系,imageView显示的内容就会有所改变,达到我们想要的效果。 […]
尽管facebook拥有有关如何进行社交登录的文档,但如果不搜索其他资源,我仍然无法完成。 它的文档中缺少某些部分。 AppDelegate.swift中缺少的代码 在LoginViewController.swift中创建自己的按钮 StoryboardID用于LogoutViewController.swift返回 成功登录。您还可以使用FBSDKAccessToken.current().userID打印用户的facebookID FBSDKAccessToken.current().userID 事情并不难。 只是缺少了一些部分,使如此简单的任务变得有些困难。
这是与了解您的计算机及其软件相关的一系列博客文章中的第一篇博客文章。 目的是进一步了解Swift的内部,性能和性能。 我们将介绍计算机(数学)的基础知识,以及结构,数组和快速优化。 这篇文章将介绍位,字节,整数和数学。 位 在计算中,一切都是二进制的。 迅速地, 0b前缀表示字节文字的开始。 然后,所有数字( 0或1 )将字节中的位表示为小端。 0b00000000 该字节为0 ,因为所有位均为0。 字节序 这些位按从大到小(小端)或从小到大(大端)的顺序排列。 Endian,即列表中的最后一位,即列表中最小或最大的数字。 0b10100000 小尾数中的以下数字是128 + 0 + 32 + 0 + 0 + 0 + 0 + 0 ,因此为150 但是,在big endian中,这是1 + 0 + 4 + 0 + 0 + 0 + 0 + 0 ,因此是5 。 最低位代表1 ,每步乘以2 。 […]