访客模式是来自臭名昭著的“四人帮”的设计模式,我曾多次使用它来解决一些棘手的问题。 它主要解决了问题,但是我不能说我曾经喜欢访客设计模式。 它产生了许多自己的问题,您可以通过创建更复杂的访问者模式来解决。 这是我与模式有关的问题之一。 它很快变得复杂,我讨厌编写复杂的代码。 让我们看看一些情况,这些问题是我在C ++中使用访问者模式解决的,以及在使用Swift编写相同代码时如何完全避免使用访问者。 谓词编辑器 谓词是返回布尔值的运算符或函数。 以下是将两个表达式与比较运算符组合在一起的谓词: a + 3> 4-2b 在内存中,我们可以将其表示为对象树。 这里的每种颜色代表对象或类的不同类别。 在Mac OS X上,有许多应用程序示例支持通过GUI编辑器创建谓词。 一个示例是iTunes中的智能播放列表。 想象我们想用C ++创建这样的编辑器。 因此,我们需要一个GUI来允许我们组成谓词。 一旦获得谓词,我们可能希望过滤MP3歌曲列表,以查找可以归类为90年代音乐的歌曲。 让我们考虑一些简单的事情。 我们如何表达25首播放最多的歌曲的谓词? 以下是iTunes的一种方法。 因此,让我们将其范围缩小到谓词: 播放次数> 0 在C ++代码中,我们可以表示为: 表达式* plays = AttributeExpression(“ plays”); 表达式*零= ConstantExpression(0); 谓词* pred = LargerThanPredicate(plays,zero); playsongs = allsongs.filter(pred); 因此,要使用谓词,我们要处理Expression和Predicate对象。 但是,要使用GUI构建谓词,我们需要不同的对象来表示各个行的GUI。 我们可以有一个PredEditorRow类来代表每一行的GUI。 但是,有许多不同种类的行。 谓词可以任意嵌套,因此我们需要复合行。 让我们重新访问我们的第一个音乐智能列表。 90年代的音乐谓词看起来像这样: 1990 <年<1999 […]
在移动应用程序开发中,可靠的架构模式在更快地构建应用程序中起着重要作用。 因此,为了确保多个应用程序中现有代码的质量和可重复使用性,公司开始构建可重复使用的软件开发工具包(通常称为SDK)来开发移动应用程序。 对于iOS,Apple已经创建了无数SDK,供应用程序开发人员构建应用程序,但公司仍需要构建自己的自定义iOS SDK,以在其应用程序中共享产品特定的通用代码。 为了加快YOOX NET-A-PORTER GROUP(YNAP)的iOS应用开发速度,我们构建了通用的iOS库,这些库可以在NET-A-PORTER,MR PORTER,YOOX,THE OUTNET和30+以上的多个iOS应用之间共享我们为其经营数字商店的品牌。 主要的iOS SDK之一是我们的客户端应用程序与后端API之间的一层,在本文中,我们将其称为“ iOS-SDK”。 什么是iOS-SDK YNAP在App Store上提供了许多iOS应用程序以及为我们的同事服务的许多其他企业应用程序。 我们希望为同事们反映客户的经验,同时减少重复编码。 为此,我们决定构建一个通用的iOS-SDK,以方便在我们的客户和企业应用程序之间共享。 这也使我们可以通过在方法和返回类型方面定义一组行为来简化构建过程。 然后,使用SDK的人只需为每个应用实现适配器。 这意味着iOS-SDK是iOS库的集合,可使用CocoaPods或Carthage轻松分发。 我们仅用Swift编写了该库,并且它具有一个内置的示例应用程序,可让我们测试特定于客户端的功能。 为什么我们需要iOS-SDK的持续集成和持续交付 由于iOS-SDK代码可能会影响多个客户端应用程序,因此必须确保iOS-SDK的代码质量满足所有受支持的应用程序的要求。 为此,定期运行可靠的自动化测试非常重要,以确保一个客户端的代码更改不会对其他客户端产生负面影响。 为此,我们需要持续集成(CI)来获取对iOS-SDK代码库所做的任何更改的即时反馈,并需要持续交付(CD)来相应地更新客户端应用程序。 通过将CI / CD添加到iOS-SDK,我们可以获得有关Swift代码更新的早期反馈,并定期在客户端应用中测试新功能。 为SDK实施CI / CD实践与对普通iOS应用同样重要。 我们开始通过构建自动化,自定义脚本和使用Travis CI功能在iOS-SDK库上实现CI / CD。 我们的iOS-SDK CI / CD火箭现已准备好发射。 iOS-SDK部署自动化 我们的iOS-SDK是一个Swift库,我们使用CocoaPods或Carthage分发它。 手动部署iOS-SDK库是一个耗时,重复(而且很无聊!)的过程。 以前,每当我们要发布新版本的iOS-SDK时,开发人员都需要经历手动过程。 我们需要克服这一点,并开始寻找可以执行以下操作的自动发布过程: 当源代码在Master分支中合并后,会自动构建该库的新版本,运行所有自动化测试并自动使用Podfile或Cartfile提到的版本创建标签 使用Github Changelog.md发行说明自动制作该库的Github版本 将库的新版本推送到YNAP的专用Cocoapods存储库,以便我们可以从专用存储库下载规范 在Slack频道上自动宣布该库的新版本 我们通过结合使用自定义脚本,Fastlane工具和Travis CI来实现这一目标。 在此过程中,几乎没有引入任何更改来帮助自动部署iOS-SDK。 iOS开发人员必须在每个.podspec文件中维护Changelog.md文件以获取发行说明和凹凸版本,以便部署脚本将读取此信息以实现发行自动化。 我们可以从.podspec文件中读取版本,并使用Fastlane在Github上创建一个自动标记。 $ […]
我现在要来写一系列关于iOS程式开发的文章。不是为了教学,而是为了把我懂的知识整理起来,系统化。里面的概念可能跟别人讲的不一样,不保证我写的是对的。 我会用英文来表示技术性词汇。 首先,我是用Swift来写app的。Swift是一种编程语言(程式语言)。编程语言是一种写给编译器(编译器)看的语言,而不是电脑硬体直接看得懂的。硬体看得懂的语言叫做二进制代码(二进位码),而编译器的作用就是把编程语言编译成二进制。 Binary就是长这个样子— —只有1跟0。很容易的,要人类用这种方法去写程序,有点太麻烦了,所以才会有人类更容易理解的编程语言出现。这些编程语言大多都是都市套用而Swift在编程语言当中又是属于高阶的,也就是一种高级编程语言。简单地说就是越像英文就可以阶入,而Swift确实是非常接近口语英语了。 Swift社区特意写了一个API设计指南,去推广“清晰度之上”这个美学观念。什么意思呢?就是说在用Swift写代码的时候,最好写得清楚一点,让其他读代码的人可以更容易理解你在写什么。 Swift的基本语法有以下几个。 分配(分配) 将单等号(=)后面的东西分配(分配)给单等号前面的变数/常数。用白话来说的话,就是把一个东西放到容器里的过程。某种说, a = 1 就是把「1」这个值放到「a」这个容器里面的意思。 呼叫(呼叫) 要求执行某个功能(函式)的意思。函式简单来说就是一个动作,某种说: print(a) // 把 a 的內容印出來。 当中, print是函式的名字,而加上括号就代表你要机器在这里去执行这个函式。这,光是写print ,该函式是不会被呼叫的,还要加括号才行。最后,括号里面的东西就是你要给函式的东西。 有没有加括号,差异真的很大。某些说以下这两句所代表的意思完全不同: // 呼叫 randomInt 函式並將其輸出值指派給 a。 a = randomInt() // 將 randomInt 函式本身指派給 a。 a = randomInt 然而,对有参数(参数)的功能来说,加括号不代表一定就是调用,还要丢参数进去才算。有时说以下语句都是将combine这个功能分配给a的意思: // 省略參數列表。 a = combine // 把參數名都寫出來。 a = combine(a:b:) 参数又是什么呢?首先,功能就像是一台小机器,被呼叫的时候它就会去执行它里面的程序代码,一行一行。最后,它会输出一个值,或者说return(传回)一个值。而参数,就是一个功能在执行时需要输入的一组值。例如说,如果我们把combine这个功能的功能设计成把两个输入值加起来再输出,那这两个输入值就是它的参数。以下就是呼叫combine的句型: // 輸入 1 […]
在编写程序时,根据编码最佳实践,代码应具有可读性,可维护性和可测试性 。 “无法测试的代码存在缺陷。” 作为iOS移动应用程序开发人员 ,我们经常编写许多涉及UI,网络,持久性和其他业务逻辑的代码。 在本文中,我们将共享我们的网络层实现,该实现处理API / web-service交互,以帮助编写有关网络层逻辑的测试。 在编写测试之前,我们需要熟悉如何将网络层代码与UI相关代码和其他业务逻辑分离。 没有这种去耦,就不可能孤立地测试网络层。 网络层包括: 准备请求 (URL,方法类型,标题,参数) API调用 (NSURLSession) 解析响应 (将数据转换为模型对象(或返回错误消息) 网络层测试使我们能够确保API请求已正确形成,并且API响应解析已按预期完成,从而模拟了Web服务器。 根据我们的测试方案,我们将需要进一步分离网络层。 为此,我们将创建一个APIHandler,该APIHandler用于发出请求并解析响应。 遵循APIHandler ,请参阅以下有关LoginAPI的示例请求/响应处理程序。 Path() -不用担心Path()。login 。 Path()只是一种根据DEV / TEST / RELEASE环境返回特定端点的方法。 更多详细信息可以在这里找到。 所有API请求都将包含url,httpMethod,参数和标头 。 set —由于上述示例API调用是一种post方法,因此我们需要准备httpBody,这是通过RequestHandler协议扩展来完成的。 BaseRequest对于所有常见的请求配置(例如标头,timeoutInterval等),我们可以创建一个符合Request Protocol的 BaseRequest类, 如下所示。 设置好通用配置后,每个API可能会有要在API请求中发送的自定义参数。 对于需要身份验证令牌的任何API,我们可以使用AuthRequest对象而不是BaseRequest对象,以便API请求具有auth-token。 现在,我们已根据需要准备了URLRequest 。 准备好API请求后,我们可以调用API(我们将在一分钟内逐步完成)。 放置API调用并且服务器响应后,我们将收到需要根据我们的要求进行解析的原始响应。 通常,我们将原始响应解析为模型对象。 为此,我们可以使用泛型来处理ResponseHandler中的响应 。 上面的代码处理来自服务器的success , known-error和unknown-error api响应 为了调用API,我们编写了一个通用类APILoader ,该类使用可达性库处理网络错误,URLSession和Internet连接错误,如下所示。 我们可以将LoginAPI对象传递给通用APILoader […]
在我迅速发展的初期,我只是通过在代码中编写类,变量,属性和其他成员而感到很享受。 我不知道限制代码块,类或模块的访问。 😛基本上,那时我不关心它们,直到我看到一些怪异的关键字(“ fileprivate ”,“ internal ”等)被我的一些高级开发人员使用以及在许多GitHub开放库中使用。 访问控制可帮助您防止其他源文件和模块中的代码访问您的代码(可以是类,变量,属性和其他成员)。 您可以防止覆盖代码中声明的成员,并隐藏实现 。 您可以处理可以由哪个特定模块或文件或成员访问的代码。 swift中有不同类型的访问级别。 如果您尚未定义默认访问级别,则默认设置为“ 内部 ”。 开放访问是最高(最低限制)访问级别。 –如果将类或任何成员定义为开放,则可以从任何模块或源文件访问它。 –您可以通过导入该模块来使用。 –您还可以覆盖该类或类成员以及对其进行子类化。 Public几乎与Open类似,但是只能在定义它们的模块内进行子类化。 –在定义模块之外可以访问公共类成员,但不能重写。 例如 : //其他模块的功能(例如您使用cocoapods或carthage安装的某些库) 打开func dummyFunction(){ print(“我的类型是开放的,所以任何人都可以覆盖我。”) }公共功能tempFunction(){ print(“我的类型是公开的,因此没有人可以覆盖我。”) } //让我们在导入必要的模块之后尝试在我们的项目swift文件中覆盖此功能。 重写func dummyFunction(){} //编译器将允许 // //编译器 将给出错误,因为它是未打开的公共类型 覆盖func tempFunction(){} <- 错误…….错误……错误 其他例子: 导入UIKit 类MyViewController:UIViewController { 覆盖func viewDidLoad(){ super.viewDidLoad() } 覆盖func viewWillAppear(){ super.viewWillAppear() } } 诸如viewDidLoad,viewWillAppear之类的某些函数也使用开放式访问进行定义。 […]
在移动应用中,当我们向后端请求图像时,通常不会收到准备好渲染的图像。 我们会收到一个URL。 我们访问此URL,获取图像数据,实例化图像并进行渲染。 原因很明显,如果我们在HTTP响应中包含可能的数千千字节的图像,则响应大小将比URL的数十个字符大得多。 此问题通过间接解决。 现在,如果我们的应用程序需要将图像上传到后端,则通常会与该图像一起发送多部分请求,或者使用主体中以base 64编码的图像发出发布请求。 有时,我们甚至将图像上传到第三方服务器(例如Amazon S3),该服务器为我们提供了一个URL,并将其转发到后端。
条件ต่างๆมากมายซึ่งแน่นอนในแอปพลิเคชั่นเราก็จะเต็มไปด้วย否则声明จุดประสงค์ของหัวข้อนี้จะกล่าวถึงการใช้错误处理ช่วย นการลดความซ้ำซ้อนและแยกส่วนLogicกับส่วนแสดงผล ยกตัวอย่างเงื่อนไขดังนี้ รัฐบาลกำลังจะปล่อยเงินกู้ดอกเบี้ยต่ำพิเศษให้แก่ประชาชนโดยมีเงื่อนไข 1ผู้กู้ต้องมีรายได้ขั้นต่ำ15,000บาทต่อปี 2ผู้กู้ต้องมีรายได้ไม่เกิน10,000,000ต่อปี 3มี消息แจ้งเตือน用户เมื่อไม่ผ่านเกณฑ์ที่กำหนด 5,000ยหากมีรายได้น้อยกว่า15,000ให้แจ้งข้อความว่าขออภัยรายได้ท่านน้อยกว่าเกณฑ์ที่กำหนด ,000,000ยหากมีรายได้มากกว่า10,000,000ต่อปีให้แจ้งข้อความว่า“ขออภัยรายได้ท่านมากกว่าเกณฑ์ที่กำหนด ซึ่งหากเราเขียน功能ขึ้นมาตรวจสอบช่วงของรายได้ก็จะมีหน้าตาประมาณนี้ 需求逻辑功能验证需求警报功能 handlingนี้เรามาลองใช้错误处理เข้ามาช่วยเพื่อแยกส่วน验证ออกมา 1ออกแบบรูปแบบของErrorที่ต้องการ 2สร้าง逻辑功能 3เรียกใช้功能 สิ่งที่เปลี่ยนไปคือ 1ส่วนของLogicและส่วนของ警报消息แยกส่วนกันเป็นที่เรียบร้อยแล้ว 2收入水平验证收入范围收入范围收入
iOS开发如何解决窗口设计问题 雷锋的网络(“雷锋的网络”搜索受到公众关注):本文由掘金翻译翻译者llp0574道格拉斯预防棚架的道格拉斯·希尔,校对:yifili09,格兰宁。 这开始重新掘金,未经许可禁止转载。 IOS 9页面以无法重现活动视图控制器的方式显示,并且当内部表单,弹出式动作列表和活动UIKit视图控制器开始显得不太连贯时。 我们向Apple展示了两个Radars:无法显示填写表单的活动视图控制器,以及读取警报控制器的popoverPresentationController属性会更改行为。 iOS交互准则指出: 不要在模式视图的窗口中显示。 由于警告窗口可能是一个例外,因此它不应显示任何内容。 在导致弹出模式视图的操作之后,真正需要显示的情况很少,应该先关闭弹出窗口以进行显示。 和 仅弹出一次。 显示更多弹出窗口会使交互突然变得混乱和混乱。 不要显示级联或层次结构,一个又一个。 如果需要显示一个新窗口,则首先弹出关闭窗口。 在具有全屏弹出窗口的正常环境和紧凑环境的水平级别中,应将视图控制器样式呈现为弹出窗口。 样式UIActivityViewController和UIAlertController的动作列表遵循相同的规则:显示为弹出窗口或拉动表。 那么,如果弹出窗口显示一个活动的视图控制器或列表,将会发生什么呢? 该文档论据的交互式指南似乎是矛盾的。 在iOS 9的页面描述中,我们注意到一个视图控制器显示了一个填写此表单的UIActivityViewController表单,想知道这不是我们在默认行为之前没有注意到的问题吗? 还是我们无法定制实现的事情? 对于大多数视图控制器,在为currentContext或overCurrentContext设置当前视图控制器modalPresentationStyle所需的弹出窗口或窗体内显示。 但是对于UIKit控制器提供的某些视图(例如UIActivityViewController和UIAlertController),它们已经赋予了自己的样式,而modalPresentationStyle的更改将被忽略。 通常,以规则的宽度,紧凑的宽度将弹出窗口UIActivityViewController显示到透明表中。 但是,如果一个常规宽度的视图控制器从紧凑视图的宽度显示到控制器将发生什么情况? 这将是要在iPad上显示的窗体或弹出式视图控制器modalPresentationStyle,或者是使用overrideTraitCollection属性的自定义显示控制器,然后该控制器将显示UIActivityViewController。 行动清单 首先,我们看一下UIAlertController。 具有流行风格(下面,通过拆分视图以供参考)的图视图控制器(蓝色),显示第二个表单样式(顶部)视图控制器(粉红色)。 然后显示第二种视图控制器操作警告控制器列表样式。 尽管我们希望使用显示样式列表来显示操作列表(而不是pop),但是由于关注点分离的优势,我警告控制器popoverPresentationController.sourceView和popoverPresentationController.sourceRect已设置,视图控制器显示了如何避免做出假设。 它应在应用程序的其他部分全屏显示中执行,视图控制器不应控制这些操作。 出于好奇,我试图注释掉popoverPresentationController的定义,以至于出现意外情况: 只读警告控制器popoverPresentationController width属性即使在紧凑的环境中也可能导致,它将显示为弹出窗口。 如果要执行此操作,请确保查看控制器的显示环境,因为如果您要从常规环境中显示一个未设置警告宽度的警告控制器,UIKit将抛出异常。 请记住,在紧凑宽度的环境中渲染视图控制器时,在显示可能被更改时被激活时,会触发显示。 我提交了一个rdar:读取警报控制器的popoverPresentationController属性会更改行为。 iPhone 5手机壳Ted Baker Ted Baker iPhone 5手机壳 Active View控制器 使用UIActivityViewController做同样的事情,并指定弹出源信息如下所示: 与页面的行为不同,我发现控制器将窗体的活动视图显示为弹出窗口,控制器上的弹出窗口显示在窗体的活动视图中。 这是iOS 10,iOS 9中的新行为,是从另一个窗口显示一个弹出窗口。 使用相同的技术访问popoverPresentationController不会导致UIKit抛出异常,指出“必须为此窗口提供位置信息”。 结论 […]
问题 在oui.sncf(法国和欧洲的火车票预订主要应用程序)上,我们的主要工作是显示服务器发送给我们的内容,大多数视图也是动态的。 此外,该应用程序经常会更新为新功能,甚至静态视图也会不断发展。 因此,我们决定使用UICollectionView! 它功能强大,动态且可自定义。 但是,当有很多不同的项目时,例如在Voyages-sncf.com应用程序中,Apple的面向indexPath的实现可能会变得混乱。 代码重复,切换大小写,难以维护,更新期间存在indexPath错误的风险…… 解 我们已经建立了一年的框架,以简化和加快这些UICollectionView屏幕的开发。 该库的主要目标是在一个文件中拥有一个可读的dataSource,它表示collectionView内容。 我们将其称为Collor , Coll [ ectionViewDescript] 或 。 https://github.com/voyages-sncf-technologies/Collor 科洛尔做了两件事: 首先,它提供了基于MVVM的可伸缩微体系结构,以组织代码并避免重复。 然后,它提供了一些功能,以便删除collectionView实现所需的许多代码,例如单元格注册等,并轻松更新collectionView:删除,插入,重新加载,比较等。 建筑 为了描述collectionView,一个collectionData对象,它继承自CollectionData 用来。 它分为部分和项目。 UICollectionView数据源要求collectionData知道节的数量,节中的项目数以及要出队的单元格。 collectionData对象包含一个SectionDescriptor数组:SectionDescriptor实现协议SectionDescribable ,并使用Apple的FlowLayout处理某些节功能,例如sectionInset , minimumInteritemSpacing和minimumLineSpacing 。 SectionDescriptor还包含一个CellDescriptor数组。 例如,在Voyages-sncf.com应用程序上,每次我们需要一个简单的标签单元时,我们只需创建一个新适配器即可实现VSCollectionLabelAdapter协议, VSCollectionLabelAdapter用UICollectionViewCell及其先前创建的描述符。 适配器管理标签的样式; 标签会使用Autolayout填充整个单元格,并使用NSAttributedString.boundingRect()计算其高度。 一些代码来解释我们做了什么: 确实,您可能有一个描述符,该描述符以最小的变化处理相似的单元:左侧或右侧的图像。 因此将有两个单元,但是一个描述符和一个公共适配器协议。 Collor是一个面向协议的框架。 可以在示例中实现新协议BackgroundDrawable ,而不是在节描述符中添加属性,因此可以在其他自定义布局中重用… 协议BackgroundDrawable { var backgroundInset:UIEdgeInsets {获取设置} } CollectionView更新 如果您已经必须在tableView或collectionView中实现扩展/折叠,那么Collor应该会让您感兴趣。 实际上, Collor提供了一些轻松添加,删除,重新加载节或项目的方法。 不再需要使用IndexPath ,您只需操纵描述符引用, Collor即可完成工作。 […]
之前,我们谈论过中央车站的调度和关闭。 入门Swift编程第11部分-大型中央调度和关闭 以前,我们了解了代码结构,可读性和其他一些原理。 medium.com 这是一个艰难的过程,但您会很高兴知道所有困难的事情都已经过去了。 本文将介绍一些新概念,以帮助您提高代码的可读性,简化代码,并在Self与self领域中提供一些背景,而不是大写S 类型别名有助于使我们的代码更具可读性,并使我们作为开发人员的生活更加可忍受。 您可能会理解这在其他语言中被称为alias或typedef ,但是在Swift中我们使用typealias 。 Typealias只是将类型重命名为更易于使用或理解的名称。 在代码中,您可以使用typealias来获取原始类型并将其重命名为更适合您的上下文的名称。 让我们看一个例子: 接下来,属性观察器很不错,因为它们可以帮助您自动执行每次变量更新时需要发生的某些事情。 财产观察员基本上观察财产的变化。 它们有两种形式。 willSet —在设置变量之前执行操作 didSet —设置变量后执行操作 我几乎从未使用过willSet ,但是我didSet都在使用didSet 。 属性观察器适合您的代码,如下所示: 是,有一点不同! 即使看起来很细微,差异也很大。 在类和结构中,有时我们必须从该实体拥有的方法中引用该实体的属性。 在这种情况下,必须使用小写的self 。 让我们看一个例子