Tag: swift

快速提示:基于闭包的CollectionType API

我们每天处理数据集合,无论它们是字典,数组还是集合。 使用集合会导致很多样板工作: for-in语句,临时存储变量和许多代码行。 Swift引入了一组新的,基于闭包的功能性API,用于处理集合。 这些方法减少了样板代码,有助于突出显示重要信息并提高可读性。 这些方法也是可链接的,因此您可以轻松组成高级逻辑。 核心方法 forEach(_:) 这是一个简单的迭代器,它以与for-in相同的顺序调用self每个元素的闭包。 [“ a”,“ b”,“ c”,…,“ z”]。forEach { print(“ \(element),“) } //打印:a,b,c,…,z, map(transform:) 这将返回一个Array,其中包含将转换映射到self的结果。 let upperCaseLetters = [“ a”,“ b”,“ c”,…,“ z”]。map { 返回element.uppercase } // upperCaseLetters为[“ A”,“ B”,“ C”,…,“ Z”] filter(predicate:) 这将返回一个数组,其中包含满足提供的谓词的self的有序元素。 let元音= [“ a”,“ b”,“ c”,…,“ z”]。filter { 返回元素==“ a” || 元素==“ e” || 元素==“ i” […]

为什么要抽象任何iOS第三方库

如果您有iOS应用,则可能已集成了外部库和工具来帮助您更快地准备好产品。 但是,您的iOS体系结构和快速代码不应依赖于这些库。 与许多iOS开发人员一样,您已经为应用程序实现了外部服务。 它可能是诸如Stripe之类的支付系统,诸如NewRelic或Crashlytics之类的监控工具,也可能是诸如Google Analytics(分析)之类的跟踪平台。 这些工具很棒,但是,现在您必须切换到新服务。 这是否意味着您有数小时来重构方法? 您是否需要重写数百行代码? 如果是,那么这就是我们应该始终为外部服务抽象您的实现的原因。 在此演示中,我将展示如何通过Firebase集成将其切换到Fabric来记录事件。 这种方法包括如何抽象化实现以将第三方库包含到我们的代码中,并使其更易于迁移。 为了准备用于迁移的代码,我们需要抽象一些元素:要发送的事件,记录器,以及可能还需要经理来使所有内容保持单一状态。 假设我们有3个经典事件,分别登陆首页,注册和登录。我的视图可能如下所示 import UIKit import Firebase import UIKit import Firebase class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() FirebaseApp.configure() } class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() FirebaseApp.configure() } class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() FirebaseApp.configure() } override […]

转移iOS应用程序的副作用– iOS开发提示和技巧

当您销售长期开发的应用程序的时候到了,或者您即将接管一个应用程序时,您可能不必担心过渡过程。 尽管Apple已经详细描述了这些步骤,但是您应该在开始过渡之前考虑潜在的后果。 您还应确保该应用程序符合所有条件并符合转让条件 。 最重要的是,该应用程序必须至少具有一个已发布到App Store的版本,并且该应用程序的任何版本都没有使用iCloud权利或Passbook权利 。 备份数据 将应用程序移至新帐户后,旧帐户将不再可用 。 这意味着启动器将丢失有关该应用程序的所有信息,包括元数据,在App Store上可用的日期,定价,销售或下载统计信息。 您应该备份所有这些信息以作记录,因为过渡后将无法取回这些信息。 做好准备 如果您的应用程序使用以下任何功能,则需要执行一些其他操作: 可自动续订的订阅 -如果应用程序使用这种订阅,则可能会验证其有效性(例如后端)。 为了确保收件人在过渡期间能够验证订阅,发起方需要在启动传输之前生成特定于应用程序的共享密钥,并与收件人共享代码,以便他们可以设置自己的验证。 应用传输完成后,收件人应生成一个新的共享机密,以便组织外部的用户不再可以访问它。 Apple Pay-商户ID不会随应用程序一起转移。 只要原始证书有效,交易就继续成功。 在提交更新时,收件人需要生成一个新的商家ID。 钥匙串 -在过渡后提交第一次更新时,您会收到一封电子邮件警告,提示可能会丢失钥匙串访问权限 。 应用转换后,团队ID更改,因此应用标识符从[old-team].pl.brightinventions.app变为[new-team].pl.brightinventions.app ,这导致丢失了钥匙串访问权限。 用户更新他们的应用程序后,它将找不到身份验证令牌并要求重新登录。 钥匙串共享也仅在更新应用程序之前需要继续工作,并且需要替换为收件人创建的钥匙串组。 推送通知 -不会传输用于推送通知的客户端SSL证书,因此收件人需要创建自己的证书并将其上载到其推送通知服务(后端,Firebase等)中。 此外,如果某个应用程序是跨应用程序多人兼容性列表的一部分 ,它将不再与其他应用程序兼容或出现在其他应用程序的列表中。 同样,如果某个应用程序是该应用程序包的一部分,则您将不再能够查看该应用程序包的历史记录。 这需要时间 处理应用程序转移最多可能需要两个工作日。 在此期间,您将无法编辑应用程序元数据,权利,价格和应用程序内购买,因此您应确保在此期间不需要任何紧急更改。 转移应用程序对用户来说并不明显,并且准备充分应该不会以任何方式影响他们。 但是,您应该更新服务条款和数据保护条件,以便它们与新的所有者策略匹配。 将应用程序转移到另一个帐户并不困难,但这需要了解流程并做好一些准备,特别是如果您使用推送通知,钥匙串,Apple Pay,自动续订或当您的应用程序是跨应用程序多人游戏的一部分时兼容性列表或应用捆绑包。 最初发布于brightinventions.pl Mateusz Klimczak着,推动事物前进@ Bright发明 电子邮件Twitter Github Stackoverflow

DevScoop:十大iOS开发链接| 2018年3月5日

九十九个Swift问题 :九十九个Swift问题是一组有趣的问题,它们将帮助像您一样的Swift程序员学习和练习Swift编程语言中的逻辑编程,数据结构和算法方面的技能。 Swift键路径如何让我们编写更自然的代码 :键路径旨在允许您在不实际调用属性的情况下引用属性-您拥有对属性本身的引用,而不是读取其值。 它们在Swift中的使用仍在不断发展,并且在许多方面,它们都受到Objective-C中关键路径支持的影响,但是已经出现了一些清晰的设计模式。 如何在Swift中应用单一职责原则 :有时候,当我们学习如何编码时,很难理解类职责概念。 这是因为我们的第一个项目变得难以维护,原因是我们的代码中按类包含许多行,更重要的是,它承担了许多责任。 NSTimer的秘密世界:NSTimer的技巧和窍门,以及如何使用GCD创建可靠的替代方法。 创建您的私有CocoaPod库 : CocoaPods是管理Xcode项目周围依赖性的最常用工具。 让我们看看如何创建自己的私人吊舱。 REST-aurant上的GraphQL : GraphQL的美味介绍。 iOS开发中Ruby的历史 : Ruby通过创建CocoaPods,Fastlane等工具解决了Apple开发人员工具的复杂问题。 大多数iOS开发人员已经在他们自己的工作流程中接受了Ruby,因此Ruby不会很快退出iOS应用程序开发。 根据Alto’s Odyssey的创建者的说法,iOS游戏的发展状况 : 2015年的Alto’s Adventure出人意料。 它作为无微交易的高级游戏在iOS上发布,并在全球App Store排行榜上名列前茅。 它是由Alto团队开发的,该团队是加拿大一家名为Snowman的公司与艺术家Harry Nesbitt的合作,后者此前尚未发布过游戏。 Slack和GitHub:您的终极生产力对 : GitHub和Slack一起是您的终极生产力对,在团队对话的同时,还提供了对开发工作的更大可见性。 从Terminal.md打开Xcode工作区 :这是从终端打开Xcode项目的快捷方式。 FlippingNotch : FlippingNotch是“拉动刷新/添加/显示”自定义动画,它是使用iPhone X Notch编写的Swift。 如何知道何时应该辞职:考虑辞职? 如果是这样,您并不孤单。 美国每个月有超过200万人辞职。 容易发生的事情不会持久。 持续什么,都不容易。 如果您不想错过任何内容,请注册我的新闻通讯=> DevScoop

斯威夫特语言,布里飞解释

Swift是一种用于开发iOS,WatchOS,tvOS和MacOS应用程序的编程语言。 苹果公司宣布了WWDC 2014。 Swift设计为与Objective C语言一起使用。 我将尝试通过一些示例来简短地解释语言(并非涵盖所有要点)。 “ var”关键字清除变量; 例如:var doubleNumber:Double = 1.0 “ let”关键字清除常量; 例如:let constantDoubleNumber:Double = 1.0 在快速语言中,无需始终指定变量的类型。 通过将值分配给变量或常量,编译器可以指定变量的类型。 例如:let intNumber = 50(类型为整数),let doubleNumber = 50.0(类型为double) 要在字符串中使用不同的变量,我们可以使用反斜杠(“ \”)和括号(“()”) 例如:let numberOne = 4,let numberTwo = 5 让stringOne =“我呆在\(numberOne)楼” 让stringTwo =“我有\(numberTwo)寿” 用于数组的循环; 例如:letterAge = [8,13,11,41,38,55,78] 年龄的人{ 如果年龄<25 { println(“青少年时代”) } 否则,如果25 <年龄<60 { println(“ Mautre age”) […]

iOS 11中的自定义方案处理和WKWebview

Apple希望每个人在将其作为iOS 8 SDK的一部分发布时,从完美的UIWebview迁移到新的WKWebView 。 甚至有一个“美丽”的警告消息,并且已经存在了四年了……嗯,你知道吗? 大多数应用程序仍使用UIWebView ,因为它易于使用和完成工作。 但是,您确实应该迁移到WKWebView ,因为它由WebKit框架直接支持,它具有更多功能,并且使用了更快的JavaScript引擎。 在Glose图书中,作为读者的一部分,我们广泛使用UIWebView ,即使它是非常自定义的,也融合了本机和Web交互以及UI。 是的,新的Javascript桥(称为WKScriptMessageHandler )是WKWebView最精彩的东西之一。 书籍的核心内容仍为HTML格式。 因此,使用浏览器视图(UIWebView或其他任何视图)来显示它是有意义的。 在我们应用程序的当前版本中,我们的阅读器仍在UIWebview上运行(可耻,可耻,可耻),因为当时它是唯一可用的解决方案。 在开发版本中,我们制作了一个全新的移动阅读器,这次它基于WKWebView 。 为什么花了我们这么长时间? 因为直到iOS 11 SDK都没有办法使用WKWebView来处理自定义url方案加载。 使用WKWebView仍然有很多优点,但是自定义方案加载是一个总的障碍 。 UIWebView支持自定义NSURLProtocol ,这意味着为了提供一种自定义方式来加载自定义url方案,您只需创建NSURLProtocol的子类,然后向NSURLProtocol注册您的类。 然后,任何调用您的自定义方案的东西(例如helloworld://)都会调用您的自定义NSURLProtocol类。 然后,您负责加载和转发您的内容。 这是非常强大的功能,在我们的案例中,我们使用它来加载书籍中的各种资产,例如图像,视频等。 我们可以使用很多变通方法,但是它们大多是黑客,对于生产应用程序来说并不好。 WKWebview不支持自定义NSURLProtocol ,因此您可以注册所需的任何类,由于WKWebView请求,它永远不会被调用。 好吧! 苹果在iOS 11中添加了WKURLSchemeHandler 。 它的工作原理与NSURLProtocol几乎相同! 这是一些您可以理解的代码示例,因为老实说,您实际上并不关心上面所有的废话。 因此,首先创建WKURLSchemeHandler子类,必须实现start和stop这两个方法。 只有start方法才有意义,因为这是您要做的工作。 stop方法可以保留为空,或用于您进行任何必要的清理。 您可以访问完整的请求,因此您可以检查,从url中提取任何内容,加载所需的数据并将其转发到WKWebView 。 然后,您的内容应加载。 在创建类之后,您必须在WKWebView中注册它,并且在创建其配置时必须这样做: 一切就绪,现在您可以在WKWebView中加载任何自定义内容了!

UI测试时模拟网络通话

为了对应用程序进行UI测试,我正在研究在测试执行期间模拟所有网络调用的最佳方法。 模拟网络调用的动机是消除执行测试时的不确定性。 我们不能依靠服务器来运行,我们的测试用例所基于的数据总是一样,等等。此外,模拟所有调用将使测试运行更快。 UI测试的问题是Apple对其进行设置的方式,使您的应用在一个过程中运行,而在另一个过程中进行测试。 UI测试使用UIKit内置的可访问性功能与在单独进程中运行的应用程序进行交互。 随之而来的问题是,我们不能像通常在单元测试中那样注入模拟或存根网络调用。 根据我的阅读,有两种方法可以解决此限制。 一方面,我们可以将我们需要的所有固定装置(我们将用作响应模拟调用的文件,它们可以是json,xml等)放置在应用程序的主要目标中,并提供模拟框架以及在运行UI测试时通过环境变量,以告知我们的应用设置模拟程序。 这种方法让我有些困扰。 首先,我们仅将特殊代码用于运行测试,应尽可能避免这种做法。 这看起来从不漂亮,可能导致错误,使代码的可读性和可维护性降低。 另一个选择是在本地运行服务器,该服务器嵌入执行测试的过程中,在该过程中,我们对网络调用进行存根(stub),测试正在命中并返回固定装置。 Michal Ciurus的一则帖子详细介绍了他的操作方式。 在他的情况下,在应用程序进程中进行存根对他来说不是一个选择,因为他需要动态更改服务器的响应。 他使用swifter作为服务器,这是用Swift written编写的简约HTTP服务器。 还有其他使用其他服务器的帖子,例如Fang-Pen Lin的帖子。 Michal分享了我们需要设置服务器和对电话进行存根的类: 帮助程序类,以建立快速和存根我们的电话 然后我们简单地像这样使用它: 我们可以在helper类中设置常量存根,或者根据需要在测试中动态设置新的存根,如上面所示。 现在唯一需要做的就是告诉我们的应用使用http://localhost:8080作为调用的端点。 我有两个xconfig文件,即Debug和Release,用于设置测试和生产端点。 我使用http://localhost:8080作为端点创建了另一个UITesting。 将UITesting的特定xconfig 设置为UI Testing方案的Test Action的Build Configuration 。 现在,我们的道路上仅有一个最后的障碍,即应用程序传输安全性(ATS)。 在iOS 9中引入了Apple激励开发人员使用基于HTTPS的安全网络连接来提高用户安全性和隐私性。 但是swifter仅通过HTTP起作用。 有一种方法可以在我们的Info.plist添加异常,但是Apple建议它是临时的,从而提示开发人员确保他们在其应用程序中使用的资源的安全。 自2017年以来,除了开发人员可以证明其合理性的情况之外,Apple拒绝使用此异常的应用程序。 有一种方法可以使用密钥NSAllowsLocalNetworking为localhost添加一个不需要理由的异常,但只能在iOS 10上使用NSAllowsArbitraryLoads可以在iOS 9中使用 NSAllowsLocalNetworking should be added to the plist with iOS 10. Source. 就我而言,因为我使用iOS 10运行测试,所以只需要NSAllowsLocalNetworking 。 […]

学习指南:NSURLSession

学习如何利用NSURLSession相当困难,并且目前对我来说还很陌生。 但是,这不是通过创建详细的学习指南来强化和增强新材料的更好方法。 什么是NSURLSession? NSURLSession是Apple提供的API,供开发人员与HTTP和HTTPS协议进行交互。 NSURLSession提供了为应用程序创建会话以执行诸如数据传输之类的任务的功能。 步骤! 创建一个会话。 您可以将其视为在网络浏览器上创建新标签页。 //共享会话,一个基本请求的单例 让会话= NSURLSession.sharedSession() //默认会话,如具有更多可自定义性的共享会话 let session = NSURLSession(配置:NSURLSessionConfiguration.defaultSessionConfiguration()) // Ephemeral Session,就像没有Cookie和缓存的默认会话一样,您可以将其视为浏览器上的隐身标签 let session = NSURLSession(配置:NSURLSessionConfiguration.ephemeralSessionConfiguration()) // Background Session,在应用程序在后台运行时执行任务的会话 let session = NSURLSession(配置:NSURLSessionConfiguration.backgroundSessionConfiguration(identifier)) 2.设置请求。 打开新标签后,下一步该怎么做? 输入您要访问的URL。 *如果没有参数,则可能不需要请求 //使用NSMutableURLRequest创建一个请求,并将未包装的URL作为参数传递。 let request = NSMutableURLRequest(URL:UnwrappedURL) 3.为请求设置HTTP方法。 您可以充当一个非常基本的浏览器,并且该浏览器不知道该怎么做。 因此它需要一些帮助。 使用上面创建的NSMutableURLRequest,调用HTTPMethod POST =创建 GET =读取 PUT =更新* 补丁=更新* 删除=删除 * PUT或PATCH的使用取决于您使用的API。 //我们将以GET为例。 request.HTTPMethod […]

控制器和视图

我喜欢用代码编写UI,并且使用“自动布局”功能很容易。 但是,这给ViewController留下了大量代码。 我们可以做的一种方法是通过使用专用视图在MVC中将V与C分开。 感谢我的朋友Vadym向我展示了它。 我们可以使用generic来做到这一点,即初始化一个视图并替换该view ,我们称其为root 导入UIKitclass BaseController :UIViewController { 让root = T()覆盖func loadView(){ 视图=根 } } 现在我们可以有一个UIView子类,例如LoginView 最后一课LoginView:UIView { 惰性var textField:UITextField = UITextField()。然后{ $ 0.textAlignment = .center $ 0.borderStyle = .roundedRect $ 0.keyboardType = .phonePad }懒惰的var按钮:UIButton = UIButton()。然后{ $ 0.setTitleColor(.black,for:.normal) $ 0.backgroundColor = .lightGray }覆盖init(框架:CGRect){ super.init(frame:frame)addSubviews( 文本域, 纽扣 )约束 textField.centerXAnchor.constraint(equalTo:textField.superview!.centerXAnchor), textField.centerYAnchor.constraint(equalTo:textField.superview!.centerYAnchor), textField.widthAnchor.constraint(等于:textField.superview!.widthAnchor,常数:-20),button.topAnchor.constraint(equalTo:textField.bottomAnchor,常数:20), button.centerXAnchor.constraint(equalTo:button.superview!.centerXAnchor), button.widthAnchor.constraint(equalTo:textField.widthAnchor,乘数:0.8), […]

在Swift中通过不同的方案在项目中实现不同的应用

在某些项目中,它们可能具有相同的骨骼,但使用不同的皮肤。 要构建这类应用。 我们可以使用这种方式来实现它们。 我们无需在实现中使用预处理器宏 。 仅使用扩展名就可以取代预处理器宏。 根据情况,它可以帮助我们的代码比以前更干净。 新建一个项目 1.创建具有单个视图的应用程序 只需创建一个您想要创建的项目即可。 对于本教程,我仅使用单一视图。 实际上我们可以创建任何类型的项目 2.与现有目标重复的目标 请记住修改我们刚刚复制的目标名称,否则该名称将带有后缀的副本 3.创建新计划 必须检查可执行文件是否遵循我们刚刚复制的目标,否则该方案将使用错误的目标 4.重命名捆绑包标识符和产品名称 修改捆绑包标识符,使我们可以通过代码库分发应用程序 5.单独的Info.plist 如果我们要进行其他设置,可以复制中继Info.plist,并根据需要进行设置 6.通过类型1实施 创建协议 // SchemeProtocol.swiftimport Foundationprotocol SchemeProtocol { var schemeTitle:字符串{get} func displayMonster() } 实现分支文件。 它从主干扩展了类,并遵循了我们刚刚创建的协议 // ViewController + SchemeA.swiftimport UIKitextension ViewController:SchemeProtocol { var schemeTitle:字符串{ 返回“方案A” } func displayMonster(){ 让imageView = UIImageView(框架:CGRect(x:100,y:100,宽度:200,高度:200)) imageView.image = imageLiteral(resourceName:“ SPROUT”) view.addSubview(imageView) […]