有时我们会像类似元素一样谈论库,API和框架。 因此,我想简单地解释它们各自的含义以及它们之间的相互关系,以便您更好地理解它们。 此外,重要的是要知道SDK是Apple操作系统中的重要元素。 来吧,让我们说清楚! 图书馆 库是保存预编写代码的地方,可以调用这些代码来帮助您更快更轻松地完成工作。 该库基本上是一组元素,例如函数,类,常量,变量等,您可以在项目中使用它们来创建应用程序。 例子: Swift标准库解决了复杂的问题,并允许您编写高性能的可读代码。 这些库是用Swift编写程序的基本功能层,它们是为Swift设计的并以这种编程语言处理的一组数据类型和功能。 如果您用引号引起来的文本,例如“我喜欢制作原型”,那么Xcode将借助Swift标准库将其作为字符串进行处理。 如果输入: let a:Int = 10 ,则程序会将其解释为不带小数的整数。 例如: let sum = a + 1的结果为11。如果尝试使用let sum = a + 0.5 ,则会显示错误,因为编译器不允许常量和包含小数点后的数字。 但是,如果您编写: let b:Double = 10 ,程序将知道该数字可以有小数。 因此,如果您添加十进制值,例如: let add = b + 0.5 ,则结果为10.5。 API API(应用程序编程接口)是您的代码与一个或多个库之间的连接。 它与它所连接的库的版本有一定距离。 另外,API不包含实现细节。 例如,可能有多个库可以使用十进制Double或Float,并且每个库都有针对这些数字类型的完整实现。 尽管程序的API不会改变,但在这种情况下,会添加小数的API取决于您所使用的设备和操作系统,您将使用一个库或另一个库(对于macOS或iOs),具体取决于API。 例子: Apple Music API是音乐服务网络的一部分。 使用Apple […]
请注意 ,由于README为该库提供了很好的介绍,因此本文不会涉及Cuckoo的基础知识。 您是否编写单元测试? 你应该。 在Objective-C中为我的测试编写模拟程序似乎要容易得多。 OCMock充分利用了Objective-C的动态特性,使模拟变得轻而易举。 但是,OCMock网站上有这样的说法: 令人失望。 准确。 好吧,出发寻找替代方案。 我能找到的最好的东西是SwiftMock,但这带来了更加尖锐的失望: Swift似乎缺乏反射性,这意味着我们注定要手动做事并一次又一次地重写相同类型的代码。 因此,我采取了自己的模拟游戏。 它没有那么坏。 真。 我基于Mock协议并使用Swift的基本反射构建了自己的Mock框架,在TDD的世界中,所有人都感到很高兴。 当您编写大量代码以及应附带的所有测试时,为模拟编写样板的所有时间都很累。 我渴望更高效的东西。 然后,我被介绍给杜鹃。 Cuckoo是Swift的一个模拟框架,它使用代码生成来创建您自己编写的样板。 它具有很多功能,我认为这些功能过于繁琐和重复,无法自己完成。 它还可以确保一致性,这是我在手工模拟世界中非常缺乏的东西。 代码生成与反思 大多数编程语言使用反射来动态执行某些事情,否则我们将不得不为其编写重复的样板。 OCMock使用反射来创建模拟对象。 实际上,它不会为您要模拟的每种类型创建一个新类。 反射允许像Objective-C这样的语言来动态创建模拟,检查是否相等以及执行JSON序列化。 到目前为止,在Swift中这并不是一件容易的事。 Swift语言避免了动态行为,并鼓励使用更安全的方法。 另一方面,代码生成非常适合Swift的类型安全性。 您拥有可以被人类阅读并可以由编译器验证的代码。 起初我觉得很奇怪。 我可能没有写样板,但它仍然存在。 由工具编写并隐藏在后台。 但这似乎是像Swift这样的语言的前进方向。 诸如Sourcery和SwiftGen之类的框架使您可以为这些任务采用代码生成,否则可以通过反射来完成。 缺乏反射和强大的类型安全性意味着在减少您花在单调任务上的时间和更多时间在应用程序重要部分上的工作时,代码生成是新的入门方法。 布谷鸟使用代码生成比反射方法具有许多优势,例如类型检查,优化以及逐步调试生成的代码的能力。 不用发疯地使用杜鹃 布谷鸟已经变得更加易于使用,并且需要反复尝试。 这是到目前为止我已经学到的一些见解。 熟悉ParameterMatchers 看这个例子: stub(mock) { stub in when(stub.greetWithMessage(“Hello world”)).thenDoNothing() } 当传递字符串“ Hello World”时,我们将greetWithMessage对greetWithMessage函数的调用行为。 重要的是在此处注意,代码实际上并不期望使用String对象。 它期望一个Matchable […]
雅虎! JAPAN托管尝试! Swift Tokyo 2018报告见面会于4月12日在日本大阪举行。 大阪是日本西部的大都市。 此外,他们还支持尝试! Swift Tokyo 2018作为白金赞助商。 🙏 尝试! 迅捷会议 尝试! Swift是一个沉浸式社区,聚集了有关Swift语言最佳实践,Swift中的应用程序开发… www.tryswift.co 谢谢阅读! 😃
最近,我与一个同事一起工作,该同事试图将过滤器应用于可观察的数据库对象流。 虽然建议的代码有效,但仅限于仅针对Bool和String值进行过滤,并且它是Stringly类型的API,依靠String键映射到属性。 可行,但可能会更好 不幸的是,这不是很可扩展,也不能防止我们怪异的运行时崩溃 。 例如,假设我们运行一个更改属性名称或类型的数据库迁移,并且具有以下代码: 过滤器{中的(filterKey,filterValue) 守卫让值= object.getValue(for:filterKey)为? 整数 否则{fatalError(“无效的类型转换/无效的密钥”)} } 字符串键入的密钥现在可能已过期并且将导致错误的值查找, 或者呼叫站点将使用错误的类型🤕。 在这种情况下,您可能会出现fatalError或return nil的情况,但是无论哪种方式,这种行为都是不希望的。 因此,我们着手通过两个目标(底部的最终代码)来改善这一点: 使它通用 获得编译时安全 对于那些熟悉KVO或键值观察的人,应该立即浮现一个Stringly typed API的Stringly ,哈哈。 如果您不熟悉,则只需知道需要KVO(过去时,请参阅此处的新iOS 11版本)即可使用NSString/String键路径,这会在属性名称更改且您未更新所有的属性时导致运行时崩溃使用它的地方。 由于我们想要访问属性,因此我想看看Swift 4的新KeyPath API,它是通用的并且很棒。 KeyPaths是一种类型安全的方法,用于将引用类型的属性与评估属性分开。 这是一个例子: 在上面的代码中,我们创建对MyStruct.name的引用,并在第13行对其求值 如上所示,要引用属性,您只需要特殊字符\后跟属性引用即可。 您可以将KeyPath中的泛型视为KeyPath ,尽管它在形式上被称为KeyPath ,但是您可以理解。 然后,使用下标方法[keyPath: ]可以评估您的密钥路径所对应的属性。 有了这种类型的安全性,我们现在可以构建一个过滤器,该过滤器的初始值设定项将导致我们正在寻找的编译时安全性。 在进入代码之前,让我们考虑一下过滤器应该做什么。 与以前非常相似,过滤器应提供一种确定对象是否具有与某个期望值匹配的值的方法。 我们可能要求该值具有Equatable一致性,但这将导致限制性非常严格的API,因此我们只需要一个Matcher闭包即可。 让我们看一下脚手架代码: 过滤脚手架代码 初始化程序有两个通用参数类型: Object ,它是指将应用过滤器的对象, Type是我们将要评估的属性的类型。 使用Swift语言的类型推断,当我们为初始化程序提供KeyPath ,将能够推断出初始化程序的Type约束为PropertyType 。 为什么这么好❓ 它将强制我们的matcher闭包接受一个匹配PropertyType的参数,这意味着如果该属性的类型由于任何原因(例如数据库迁移)而沿线向下移动,则编译器将捕获匹配matcher与PropertyType的不matcher ,从而导致编译时间安全! 🙌🏾 我们现在进展顺利,但这仅仅是脚手架。 […]
服务的优先级和质量 优先级(NSOperation.queuePriority)与枚举一样,具有以下选项: 。非常低 。低 。正常 。高 。很高 服务质量(NSOperation.qualityOfService)具有以下选项: 。效用 .UserInteractive 。用户启动 。默认。 。背景 优先级和服务质量越低,与其他任务相比,任务将在队列中移得越远。 依存关系 let operationOne:NSOperation =… let operationTwo:NSOperation =… operationTwo.addDependency(operationOne) 让operationQueue = NSOperationQueue.mainQueue() operationQueue.addOperation([operationOne,operationTwo],waitUntilFinished:false) 在这种情况下,operationTwo依赖于operationOne,因此operationTwo必须在operationOne完成之前才能运行。 确保不要使operationOne依赖于operationTwo和operationTwo依赖于operationOne,否则将产生死锁。 完成区块 NSOperation完成后,它将运行一次其完成块。 let操作= NSOperation() operation.completionBlock = { 打印(“完成!”) } NSOperationQueue.mainQueue()。addOperation(操作) NSBlockOperation 块操作类似于操作,但是可以将任务放在块中,而不是将操作子类化。 这会将operation2添加到队列中,然后将operation1添加到队列中。 它将首先执行operation2的块,然后执行operation1的块。 GCD与NSO 使用GCD的好时机: 一次计算 加快现有方法 需要轻巧的东西 使用NSOperation的好时机: 需要取消并了解其运行状态 需要安排一组依赖项 同时使用GCD和NSOperation可以使您的应用程序非常时尚。 在Twitter @anthonyprograms上关注我,并查看iOS纪事以获取更多文章。
KVO是Objective-C中的一种绑定方式。 当观察对象发生变化时,允许观察者接收通知。 自动键值观察是使用称为isa-swizzling的技术实现的。 isa用于确保运行时对象的类型。 所有对象都拥有isa指针来指向对象的类。 从NSObject继承的实例在初始化时包含一个isa。 目标C 在Objective-C中很容易看到有关isa的一些信息。 初始化p1和p2时 ,它们的isa指针指向对象的类(人)。 但是,如果将观察者添加到对象中,则isa指针将被更改。 在OC运行时中,我们甚至可以重写观察对象的setter方法,并在接收到通知后执行相应的操作。 尽管KVO(Key-Value Observing)在iOS开发中是一个非常重要的概念,但是在纯Swift项目中它可能不是一个好的解决方案。 迅速 我们在项目中创建相同的类Person ,并在代码中添加观察者。 但是,如果我们忘记了一些信息,我们将收到错误消息。 致命错误:无法从KeyPath Swift.ReferenceWritableKeyPath 中提取字符串 NSObjects( p1&p2 )初始化为Person类,并且isa指针都指向Person类。 观察者需要一个KeyPath(字符串类型)来注册观察者通知。 实际上,我最近才发现了这个很棒的工具。 借助此反应式编程库,我们可以轻松实现KVO几乎相同的要求。 但是最好的办法是摆脱Swift中的Objective-C! 😆😏 下次见。 😎✨
如果您曾经玩过Core Image的过滤器API,您可能会想知道“制作过滤器并启动我自己的Snapchat需要什么!”。 有多种方法可以构建和链接核心图像过滤器以创建自定义过滤器。 但是,与自己编写相比,这有点昂贵。 当我第一次进行此旅程时,我发现API文档的许多问题仅存在于Objective-C和台式机中。 事实证明,将其转移到iOS和Swift上确实是一项艰巨的任务。 创建我们的自定义过滤器 让我们深入探讨一下Core Image Kernel文件。 在本文中,我们将创建一个CI彩色内核,该组件在名为HazeRemove.cikernel.的文件中应用雾霾滤镜HazeRemove.cikernel. 那么这是怎么回事? 我们将在每一行中对其进行分解。 但是,请务必注意此逐像素更改。 我们一次在单个像素上运行此代码,然后返回修改后的像素。 对于语法,Core Image Kernel Language位于OpenGL Shading Language的顶部,因此它将具有与Objective-C的Swift不同的规则。 kernel vec4 HazeRemovalKernel(我们指定的第一行是内核例程,因此系统知道将其交给CIKernel类执行。我们指定vec4的返回类型,因为Core Image要求我们返回此类型以进行更改输入像素正确地适合您的输出像素。 sampler src, __color color, float distance, float slope)在我们的HazeRemovalKernel函数中,我们传入一个CISampler对象,该对象被视为源像素。 __color是一种与CIContext的色彩空间匹配的颜色,如果用户启用了“ True Tone”或“ Night Swift”,则可以帮助我们使该颜色保持预期的外观。 同样对于我们的过滤器,我们以斜率和距离作为浮点。 这些只是影响典型除雾算法的过滤器参数的方式。 接下来,我们定义一些将在例程中使用和修改的变量。 首先是我们修改后的像素; 我们将此作为vec4 。 在OpenGL中, vec4是向量类型,具有4个单精度浮点数分量。 因此,在我们的情况下,它保持RGBA值。 接下来,我们定义一个浮点数,用于保存除雾算法的计算值。 d = destCoord().y * slope + distance; […]
IOS应用生命周期 每个iOS开发人员都应了解应用程序生命周期。 应用程序生命周期有助于了解整个应用程序… medium.com 与FCM服务器通信– Swift 4 最近,我正在使用基于TODO的应用程序之一,在该应用程序中,我使用firebase作为后端, www.linkedin.com 申请APNs身份验证密钥 在使用FCM的时候发现了一个问题 medium.com [CSharp]基于令牌的身份验证APNS推播范例“ MonkeyBinBin的博客 Apple于WWDC 2016发布一个关于推播服务的新功能以令牌进行身份验证并通过HTTP / 2发送推播原来的推播方式需要通过推推播凭证来进行验证,正常证明都会有有效期间当凭证过期… monkeybinbin-blog.logdown.com 本地和远程通知编程指南:与APN通信 描述应用程序如何在本地和远程发送和接收用户通知。 developer.apple.com 如何检查字符串或数字 该网站使用Cookie来提供我们的服务,并向您显示相关的广告和职位列表。 通过使用我们的网站,您… stackoverflow.com 在Swift编程语言中获取字符串的第n个字符 如何获得字符串的第n个字符? 我试过没有运气的方括号([])访问器。 var string =“你好,世界!”… stackoverflow.com 快速删除字符串中的所有非数字字符 我希望会有像stringFromCharactersInSet()这样的东西,它允许我仅指定有效… stackoverflow.com replaceOccurrences(of:with 🙂 – NSString | Apple开发人员文档 返回一个新字符串,在该字符串中,接收器中目标字符串的所有出现都被另一个给定的字符串替换。 developer.apple.com 如何在iOS中实现流畅的UISlider拖动体验 如果您曾经在Android上体验过滑块,那么拖动起来既轻松又顺畅,但是在iOS中体验却不一样… medium.com 深入理解RunLoop 最近看了很多RunLoop的文章,看完很懵逼,决心整理一下,文章中大部分内容都是引用大神们的,但好歹对自己有个交代了,花了一个周天加几个晚上熬夜完成的,有个不错还是很爽的,不多比比了,下面开始吧。什么是RunLoop … www.jianshu.com CADisplayLink 一简介1所在框架CADisplayLink和其他CoreAnimation类一样,都是在QuartzCore.framework里。2功能… www.jianshu.com 在iOS […]
本文通过使用基于代码的方法替换segues来帮助重构情节提要,该方法易于使用且省事。 让我们从大家都同意的事情开始。 故事板很棒 。 在创建出色的应用程序方面,它们确实提供了很多帮助。 但是……在管理应用程序流程和导航方面……嗯……它们可能不是。 关于情节提要的好事 通过使用Storyboard而不是独立的xib,我们可以享受很多好处。 我们可以直观地看到我们的应用程序流程。 我们可以从一个vc浏览到另一个vc,而无需编写任何代码。 我们可以享受UITableView中静态单元格的好处,否则是不可能的。 我们可以在UITableView中设计原型单元。 我们可以在多个情节提要中管理视图,然后通过情节提要引用将其连接起来,这些情节提要允许从情节提要中的一个vc导航到其他情节提要中的任何其他vc。 关于情节提要的坏事 但是,尽管有这些好处,但有时情节提要还是很糟糕: 从一个vc到它可以导航到的每个其他vc定义了硬编码的序列。 为了有条件地从一个vc到另一个vc,您需要为每个segue提供一个您需要在代码中知道的标识符,以便导航到正确的vc。 如果需要将数据从一个vc传递到另一个vc,则需要在vc中重写prepareForSegue (⚠️tight耦合)。 如果您有多个segue,则需要检查segue的标识符才能将正确的数据传递到正确的vc。 需要类型转换才能将数据分配给目标vc。 团队合作 我们团队的工作方式是,我们首先进行设计实现,然后进行api和业务逻辑集成。 因此,与情节提要相关的大部分工作都是在第一阶段完成的。 现在有时候我们需要添加在设计阶段未知的导航。 现在,我们需要在情节提要中添加适当的脚本和情节提要标识符。 这导致在集成阶段中情节提要的变化。 现在,有人可以说,更改情节提要以添加与添加Segue一样少的东西并不重要。 但请相信我。 尤其是当您在大型,不同的团队中工作时,故事板工程师和api /后端工程师的角色定义明确。 此外,我可以做任何避免情节提要冲突的事情,但是在这种情况下这是不可避免的。 在找到此问题的解决方案之后,经过几次尝试并寻找更有才华和经验的人的建议,我找到了一种最适合我的解决方案,肯定会帮助您摆脱情节提要的纠结。 走向解决方案 我有一个使用故事板脚本的原型应用程序。 我们将进行改进以最大程度地减少使用segues,并使用完全基于代码的技术从一个vc浏览到另一个vc。 如果您是一位经验丰富的开发人员,并且不想跟进,则可以在这里直接查看完成的项目。 但我鼓励您继续学习,以加深了解。 FoodOne(我们的原型项目) FoodOne是一个非常幼稚的食品订购应用程序。 它由登录和注册页面组成。 注册或登录后,您将进入可提供的饭菜清单。 您选择一餐以查看其详细信息。 如果需要,您可以通过点击屏幕上的订购按钮进行订购。 就是这样。 该项目包含两个情节提要。 主要 膳食 主板 主故事板包含登录和注册vc,以及故事板引用,用于在成功登录或注册后导航到餐单。 下图中可以看到,在主故事板上总共定义了4个segue。 膳食故事板 膳食情节提要有两个vcs。 一个用于餐单,另一个用于餐单。 在此故事板上仅定义了一个连击。 […]
通常在应用程序中,我们有以下流程:入职,登录,主要。 而且我们通常根据状态分别将OnboardingController , LoginController和MainController为根视图控制器。 我发现将MainController用作主流的容器很有用。 它可以是选项卡控制器,滑动菜单控制器或仅包含1个子视图控制器。 屏幕由子视图控制器提供,但是MainController进行以下工作 状态栏样式 我们通常需要在父控制器上调用preferredStatusBarStyle 。 参见stackoverflow.com/questions/19022210/preferredstatusbarstyle-isnt-called 应用已启用 通常,当应用程序进入前台时,我们需要获取登录的用户配置文件以查看是否有更改。 我们通过监听app did become active在MainController app did become active来做到这一点。 模拟打开 这可以是反模式。 但是在UI测试中,出于懒惰,我们可以只使用一些启动参数并检查以显示要测试的特定屏幕,因为MainController是主流的根。 登出 因为事物起源于MainController ,所以事物可以终止于MainController 。 我们可以处理logout ,清除状态,并告诉MainController告诉AppDelegate切换到另一个根控制器 原始故事https://github.com/onmyway133/blog/issues/36