Всегдаприятно,когдавприложениипродуманымелочи。 Однимизтакихнебаловажныхэлементовинтерфейсаявляетсявсплывающееменю UIMenuController中的UIMenuController 。 Вэтойстатьемыразберемся,какработатьсовсплывающимменю,скакимиограниченияеиин Собираемэлементыменю Итак,мысобираемсяпоказатьвсплывающиеменюдлянекоторогоUIView。 Дляначалаопределимся,какиеименноэлементыбудетпредлагатьнашеменюпользователю。 UIItemView 。 Черезнеговконтроллерменюпередаетсяотображаемыйтекстидействие,происходящеепривабе let item = UIMenuItem(title:“ Send”,action: #selector (sendTapped)) Рассмотримпоподробнеевторойпараметр— action 。 Окей,этоселекторнекоторогометода,которыйбудетвызванпривыбореэлементаменю。 Значит,этотметоддолженбытьгде-тореализован,ногдеименно? Еслибыэтобылаобычнаякнопка,тополучателяможноуказатьвметодеaddTarget: sendButton.addTraget( self ,action: #selector (sendTapped),for:…) 在UIMenuItem上添加UIMenuItem 。 Кудажетогдаотправится action ? Обратимсякдокументации: 未指定目标; 通过响应者链的正常遍历找到合适的目标。 响应链 ? Похоже,преждечемдвигатьсядальше,нампридетсянемногоразобратьсявпроцессеобработиисобы。 响应者链иfirstResponder UIResponder ,UIUI应用程序,UI控制器中的Любоеприложениеможнопредставитьввидеиерархииобъектовкласса Каждыйтакойобъектспособенполучатьсобытия:нажатия, 运动 -событияили UIControlEvents ,илибообрабатыватьполученноесобытие,либопередаватьегоследующему 应答 “увиерархии。 响应者 Но,преждечемпопасть,событиедолжнобытьполученокем-товпервуюочередь。 ПоэтомудлякаждоговприложениисобытияUIKitопределяетнаиболееподходящийобъектклас firstfirstResponder’омтотобъектстановится 响应者, […]
更少的样板=更快乐的开发人员 作为iOS开发人员,我像许多其他人一样从Objective-C开始。 在日常工作中,我与Swift一起工作,考虑到它的第一次迭代的增长,我发现它的多功能性很有希望。 是的,前几个版本的重大更改难以使用; 但是,这些不断增长的痛苦导致了一种更好,更高效的语言。 它的第四个主要版本在功能和社区方面都继续给人留下深刻印象。 上周,苹果举行了年度全球开发者大会(WWDC),其中展示了Swift的一些最新改进。 尽管Swift 5计划于2019年发布,但Swift 4.2具有其自身的优势,特别是在消除繁琐的样板代码方面。 枚举案例的派生集合 Swift的可爱功能之一是它具有使用类似结构的功能来扩展枚举的功能。 例如,如果我们要遍历下面显示的枚举中的所有Fruits ,则需要实现一些样板代码,其中包含数组中的所有案例。 除了每次要遍历数组时都创建一个allCases变量外,每次向枚举添加新的大小写时,我们还必须更新allCases数组。 这可能很麻烦,并且为开发人员错误留了太多空间。 Swift 4.2添加了一个名为CaseIterable的新协议,该协议默认情况下只是添加allCases数组。 我们需要做的就是将CaseIterable添加到我们的枚举中,现在我们可以遍历所有案例。 但是,请务必注意,具有关联值的枚举将无法扩展CaseIterable 。 allCases数组中的元素必须具有相同的类型,而每个枚举的关联值可以包含不同的类型。 合成等量一致性 假设有一个用户对象具有我们可能要比较的简单属性。 令人讨厌的是,我们需要User对象符合Equatable协议,然后检查两个比较对象的每个属性是否相等。 尽管这看起来很简单,但是如果我们比较具有许多属性的大型对象,这也是一项不必要的麻烦任务。 Swift 4.2现在将能够比较两个 Equatable 对象,而无需实现Equatable函数。 只要每个属性都符合Equatable ,Swift就可以推断出我们的Equatable函数。 因此,开发人员将不再需要编写该样板代码。 数组的条件一致性 以前,我们无法像上面的areArraysEqual函数中所示比较两个数组的内容,因为不将Users数组视为Equatable类型。 虽然如果我们比较两个函数数组可能会有意义,但由于函数类型不是Equatable ,而元素类型为Equatable则没有意义。 在Swift 4.2中,我们提供了一个数组扩展名,可以比较两个具有Equatable元素类型的数组。 除了数组之外,可选内容和字典还通过这种新的条件一致性提供了相同的功能。 新的随机数生成器 如果您想在Swift中创建随机数,则必须使用导入的C API,这些API需要进行严格的平台检查。 坦白说,这不是最优雅的解决方案,而要正确解决问题可能会很棘手。 Swift 4.2现在为Floats和Ints提供了新的随机数生成器功能,可以接受一定范围以准确返回随机数。 此外,现在可以从数组中检索随机元素,并且可以分别通过添加randomElement()和shuffled()函数对数组的元素进行混洗。 更多细节 这些是Swift 4.2的主要更改,但这里还没有涉及其他内容,例如新的哈希算法和协议。 如果您想了解Swift的最新功能,建议您访问https://apple.github.io/swift-evolution/以查看正在审查,接受或实施的最新更改。 一如既往,感谢您的阅读和记忆,更少的样板=快乐的开发人员🙂 资源资源 Swift的新功能– WWDC […]
预习 资源 项目 https://github.com/calmone/iOS-UIKit-component 参考 UIMenuController https://developer.apple.com/reference/uikit/uimenucontroller UIMenuItem https://developer.apple.com/reference/uikit/uimenuitem 快乐编码😄
我们尝试组织生活,因此时间表是一个很好的工具。 当我们要清洁桌子时,我们将所有东西整理好了。 这些想法我们可以应用于我们的代码,因为它是我们日常生活的一部分。 第1阶段-项目文件结构 我希望您没有一个包含.xcodeproj文件之类的文件列表的项目。 有数十个没有任何功能分类的文件。 您可以说:嗯,所有文件都应组织在项目文件中。 让我们打开百宝箱。 我们能看到什么? 像这样: 请不要说您以相同的方式进行操作。 最后一个示例由Apple提供,但是当您应该为具有大量类和职责的真实项目提供支持时–与以前计划相比,您将花费更多的时间进行搜索和准备。 此示例来自MVC范例,在该范例中我们按类型创建了分组。 结果,我们开发了一个快速的基础和难扩展的结构。 解决方案1: 我为自己找到的最好的体系结构之一是按功能分组。 Andrew Cherkashyn在他的文章:以xCode组织iOS项目文件的最佳方法中对此进行了描述。 所描述的结构更加复杂,但易于扩展。 此外,我们可以轻松地将其修改为其他架构:MVP,MVVM,VIPER…在下面提供的示例中,我们的项目结构如下所示: 阶段2 –类或文件中的结构 仅当M不代表Massive时,我才喜欢MVC模式。 苹果将其用作基本概念,并且效果很好。 如果要在模型/视图/控制器/等中更好地组织代码,该怎么办? 它们为我们提供了来自Objective-C的#pragma mark的极大可能性。 在Swift中,我们将其称为// MARK: note。 不幸的是,一些开发人员跳过了此功能。 他们使自己的代码变得肮脏,并且不将其分离为不同类型的功能。 作为示例,它可以像这样: 我们在那里: 在文件的顶部,存在方法addAlbum(_:) -一个动作方法; 在中间,有两个枚举: SegueIdentifier和CellIdentifier ; 在CellIdentifierds.下声明的变量CellIdentifierds. 完全没有标记。 我的第一意见: 解决方案2: 1.您应该在指定的具体区域内组织枚举/属性/方法/扩展/等。 另外,不要将代码放在任何需要的地方。 如果使用多个枚举,最好将其描述在一个位置,例如在文件或类的顶部: 2.使用// MARK: -仅几行代码可更快地在文件中查找内容。 快速示例: 班级成绩 恢复: 井井有条的项目加上相同的代码样式,可让您和您的团队更好地理解项目及其所有组件。 我坚持认为,清晰的代码可以提高生产率并缩短问题解决时间。 例子: […]
最近,我的伙伴对编程表现出了兴趣,因此自然而然地我推荐Swift作为一种很好的语言。 我花了很多时间亲自研究了Swift的最佳实践,我想确保她确实遵循了整个Swift社区的最佳/常见实践(我认为其中有些是最佳实践),并且没有从一些那里的教程。 即使这些教程为初学者提供了一个很好的起点,我也注意到一些确实困扰我的做法,我建议您反对。 注意 我应该指出, 这要取决于我在编写Swift代码时的最佳做法以及我在社区中的研究中所收集的内容。 我敢肯定会有人不同意,这很好。 我仍然会睡个好觉😉 首先,让我们从合作伙伴搜索初学者教程时遇到的编码实践开始。 我还将介绍与其他开发人员一起进行项目时所经历的一些经验。 1)冒号空间 尽管这看起来很小,因为它只是一个空格,但是它可以大大提高代码的可读性。 推荐的 命名:字符串 不建议 让名字:字符串 命名:字符串 让名字:字符串 简单。 在冒号之后,在类型之前添加一个空格。 2)花括号 当谈到花括号时,通常似乎是一个意见问题。 但是,在浏览互联网上的一些样式指南,Apple文档中的示例以及我个人的看法时,确实有一个赢家。 推荐的 如果isValid && list.count == 0 { …}否则,如果isValid { …}其他{ … } 不建议 如果isValid && list.count == 0 { …} 否则,如果isValid { …} 其他{ … } 要么 如果isValid && list.count == 0 […]
在初学者级别,所有开发人员都对属性有一些疑问,例如什么是属性?什么类型的属性? ,什么时候使用哪种类型? 。 所以在这里我想快速给出一些有关属性的想法。 有什么属性? “简单来说,属性具有一些您想在应用程序或班级中出于任何原因访问的值” 例如 :- var intVal = 2; var strVal =“世界你好” 因此,在这些示例中,“ intVal”和“ strVal”是具有某些值的属性。 但是现在的问题是,财产是否总是具有某些价值? 没有任何动态价值? 答案是“是的,它可以具有运行时间(动态值)”。 所以现在属性类型出现了。 它有两种类型: 1)储物 2)计算财产 它以常量和可变值作为实例。 例如 1)变量a = 5 在这里,变量“ a”存储整数值5。我们使用var关键字定义了变量“ a”,这意味着其值b可以更改。 print(a)// 5 a = 7 //更新a的值 print(a)// 7 2)让a = 5 它的工作原理同上,但不同之处在于它的值无法更改。 a = 7 //编译器抛出错误 3)var a:整数! 这里我们没有给变量a赋值。 因此,Int的默认值会自动分配给变量a。 因此,当您不需要通过任何计算获得任何动态值时,可以使用var或let来使用存储的属性。 在开发过程中,某些情况下,由于计算能力有限或其他原因,您只想在需要时才创建一些对象。 […]
对约翰和帕维尔说“早上好” : 让我们对罗伯特说“早上好” : 让我们传递false作为第一个参数:罗伯特没有“早安” 。 但是输出窗口仍然显示出GiveAname函数: 预期:调用GiveAname()获得一个字符串,并将该字符串传递给goodMorning 。 第一个参数为false ,因此在这种情况下不使用第二个参数。 但是会调用功能GiveAname 。 如果我不希望调用GiveAname ,则应该使用闭包: @autoclosure可能很有用。 例如,这是一个断言函数: func assert(_条件:@autoclosure()->布尔,_消息:@autoclosure()->字符串) 这两个参数都可以是常量,变量或闭包: 让我们将此断言函数更改为仅在允许调试时才起作用: 在现实生活中,它看起来有些复杂,但含义相同: 公共功能断言 1.函数中的参数可以用不带参数的闭包代替,并返回与参数相同类型的值。 2.可以使用@autoclosure属性标记此类关闭参数。 3.无需在此类@ autoclosure-d参数周围加上括号。 值,传递的另一个函数或表达式自动用花括号包装。 4.用作已标记的关闭参数的另一个函数只有在从函数体中显式调用之前,才执行。 闭包– Swift编程语言(Swift 4.2) 注意如果您不熟悉捕获的概念,请不要担心。 下面在捕获中详细说明… docs.swift.org
在本教程中,您将了解如何在Xcode中构造Core Data Stack来测试您的Core Data应用程序。 这并不是应该的那么简单,因为大多数测试将取决于有效的核心数据堆栈。 您不想破坏单元测试中的数据,以免干扰您自己在模拟器或设备上进行的手动测试。 访问控制 默认情况下,swift中的类具有“内部”访问级别。 这意味着您只能从它们自己的模块中访问它们。 由于应用程序和测试位于单独的模块中,因此您将无法在测试中从应用程序访问类。 如何解决这个问题 1.)您可以将应用程序中的类和方法标记为公共,以使其在测试中可见。 2)您可以在单元测试中的任何导入前面添加Swift关键字@testable,以访问该类中导入的所有内容。 @testable导入CoreDataUnitTesting 添加@testable是执行此操作的更好方法,因为您不必将您的类和方法标记为公开以进行测试。 您应用中的核心数据栈将像这样:: 类CoreDataStack { public init(){ } 懒惰的varpersistentContainer:NSPersistentContainer = { 让容器= NSPersistentContainer( 名称:“ CoreDataUnitTesting”) container.loadPersistentStores( completeHandler:{中的(storeDescription,错误) 如果让error = error as NSError? { fatalError(“未解决的错误\(错误), \(error.userInfo)“) } }) 返回容器 }() var applicationDocumentsDirectory:NSURL = { 让urls = FileManager.default.urls(用于: .documentDirectory,位于:.userDomainMask) 返回urls [urls.count-1]作为NSURL }() 公开varmanagedObjectModel:NSManagedObjectModel = […]
您最有可能阅读本文,因为您已经听说过有关单元测试的知识,并且想要了解更多。 如果您从未听说过单元测试,并且想要基本介绍,那么您来对地方了。 本文将为您提供单元测试的一般概述,并将讨论单元测试与iOS之间的关系。 什么 如果您考虑一下, 每个复杂的系统都由较小的部分组成。 您的汽车配有发动机,燃油管,油箱,挡风玻璃等。 将这些组件中的每一个组合在一起,就可以构成您的汽车。 您的汽车行驶到任何地方的唯一原因是这些组件中的每个组件都能发挥出色的作用。 单元测试中的“单元”是这些组件之一。 单元测试不仅适用于软件。 它是一个广义的工程术语,可以应用于由零件组成的任何领域,每个领域都需要完成特定的工作。 您可以将汽车拆开并在每个组件上运行诊断程序,以对汽车进行单元测试。 也许您想测试机油滤清器清除某些脏油的能力,或者您想测试气帽上的密封。 每个测试都是一项测试,您可以对组成汽车的各个单元进行测试。 这很有趣。 我已经看到“单元测试”一词在某些我从未期望使用过的领域中得到了应用。 在星际争霸中。 如您所见,这是一个非常广泛的概念。 编写有效的单元测试需要什么 一个好的单元测试需要具备以下条件。 您正在测试的隔离组件。 如果您一起测试一件事以上,那就是集成测试 。 您正在测试的特定行为。 不用说,此行为需要与您正在测试的组件有关。 成功和失败的条件。 毫无疑问。 在单元测试中,没有什么是部分成功的 。 运行时,每个单元测试必须成功或失败。 这些看起来很简单,但是您通常会发现第一部分具有挑战性。 大多数系统并不是以模块化的方式设计的,因此需要花费一些额外的精力才能有效地隔离不同的组件。 挑战:隔离组件 例如,假设您要在汽车的机油滤清器上进行单元测试。 您不能只是弹出过滤器并对其进行测试。 您必须将其卸下,将机油排入锅中,进行测试,将其放回去,然后再将油放回车中。 如此彻底地测试机油滤清器需要花费大量时间和精力,这就是为什么大多数机油滤清器都是一次性产品。 您只需在一定距离后或在怀疑它们会变坏时更换它们。 他们就像灯泡。 花时间尝试修复它们是浪费。 汽车中几乎每个组件都很难进行单元测试。 您几乎永远都不会在该级别上测试汽车的组件。 实际上,您在汽车上进行的大多数测试都是集成测试。 整合测试 集成测试是将一个或多个组件一起测试的任何测试。 当您测试汽车将清洗液输送到挡风玻璃的能力时,您正在执行集成测试。 您可以同时测试清洗液泵,清洗液管线和喷涂机机构。 除非有严重的故障,否则任何理智的人都不会花费时间或精力单独测试这些组件。 将系统分解并重新组合在一起会花费太多时间。 这个类比并没有完全映射到软件领域,但是有一个重要的考虑因素。 设计这样一个易于分解的系统需要花费额外的精力。 无论是汽车,软件还是星际争霸战,您都需要考虑这一成本。 大多数汽车都不容易进行单元测试,因为单元测试不是其设计的核心。 汽车公司不希望您一直保持汽车所有零件的良好维护。 […]
我又来了 如所承诺的,我将写关于iOS编程的第一步以及为什么我仍处于起步阶段。 首先,在35岁时,我正在尝试新事物,而不是因为体内缺乏肾上腺素。 我住在俄罗斯莫斯科,是土耳其语翻译。 但是由于叙利亚战争和ISIS的所有问题,俄土关系出现了巨大下降。 因此,我几乎失去了我的整个职业。 我一直对应用程序的开发和设计感到好奇,因此,时间和政治问题才是推动我前进的原因。 当然,这也是一个选择。 YouTube和其他网站上有大量不错的免费教程和资料。 但是其中之一,可以选择付费课程。 我也是。在网上搜索免费内容的同时,我还购买了一些付费教程。 我不会在这里列出它们,因为没有必要。 我把适当的反馈留在了原本应该的地方。 对于进一步的提升和建议,我将在以后的某个时间发表另一篇文章。 诺言。 后来我知道,我的方法是完全错误的。 这就是为什么:我通过阅读文章和扫描带有代码示例的教程,重复和重写它来开始学习Swift编程语言和iOS开发。但是我从来没有实现我在自己的项目中学到的东西。 实际上,那时没有“我自己的项目”之类的东西。 所以我退后一步,考虑了整个情况。 简而言之,我只是复制粘贴代码,然后将其保留在那里,实际上我在几天之内就忘记了之前学到的东西。 对每个API和UI元素一次又一次地这样做是没有意义的。 当然,我刻苦和无用的学习的另一个原因是,我对于这个行业来说已经很老了,而且比心脏病发作还年轻。 然后,我做出了一个决定,只学习那些将对解决那些在那个特定时刻困扰我的特定问题有用的东西。 但是首先,我需要自己的项目。 我可以使用的真实应用程序。 我看了一些教程,并从不同的应用程序和教程中汲取了一些想法(偷:),我想到了一个开关的想法,它将能够打开和关闭,发出声音并在特定时间后切换功能会更改背景色和带有令人鼓舞的短语的标签。 而已。 没有花哨的东西。 没有数英里的代码。 只是iPhone的一种烦躁类型。 我找到了开关图像,并使用Sketch绘制了它们。 使用该图像创建了一个简单的应用程序图标。 并开始编码。 为此,我学习了如何在打开开关时添加声音,如何更改UIImageView的图像以及如何更改背景。 就像那样,逐个问题地提出了我的第一个简单但我自己的iOS应用程序。 这是我对那些新手和新生的建议。 不要将时间浪费在仅仅学习基础知识上。 只是想出主意,无论它多么疯狂或显而易见。 然后尝试通过克服障碍并解决问题来制作该应用。 逐一。 一步步。 今天就这样! 有一个很好的尝试和错误。 问题越难解决,满意度就越高!