Tag: 编程

iOS上的事件传递:第1部分

如果您的iOS应用程序可以处理轻击,滑动,平移或任何其他外部交互,则它使用的是幕后事件。 这些事件采用的路径是一个定义明确的过程,我们将研究它的工作方式。 当调试一些棘手的问题(涉及文本输入或远程控制事件)时,了解此过程的工作原理很方便。 您甚至可以使用此知识使自定义数据流通过您的应用程序。 这是有关事件传递的系列文章中的第一篇。 它将涵盖触摸处理,如何将简单的触摸转变为通过应用程序传递的事件以及如何为组件提供处理该事件的机会。 触摸处理 触摸事件是iOS应用程序处理的事件的主要形式。 我们每天使用的API隐藏了许多如何处理触摸的细节。 了解如何在应用程序中传递这些事件可以帮助确定应用程序的构建方式。 您甚至可以使用此基础结构传递自定义事件。 命中测试 在讨论事件传递时,要讨论的第一件事是系统如何处理触摸事件以及这些事件通过应用程序的路径。 一旦用户点击屏幕,事件就会开始。 在适当的组件可以处理触摸之前,系统需要确定在何处发生触摸以及谁在响应该触摸时首先遇到裂缝。 这是命中测试起作用的地方。 命中测试过程中涉及的方法是hitTest:withEvent:和pointInside:withEvent:。 hitTest:withEvent:使用pointInside:withEvent:来确定要命中的测试点是否在其范围内。 如果不在边界内,则返回nil并跳过视图层次结构的整个分支。 如果测试点在范围内,则在每个子视图上调用pointInside:withEvent:。 对于从pointInside:withEvent:返回YES的子视图,将调用hitTest:withEvent:。 原始hitTest:withEvent:调用的最终结果是子视图之一或self的结果(如果其所有子视图均返回nil)。 采取以下视图层次结构: 假设用户在View E中轻按。该过程从View A中的hitTest:withEvent:开始 。 pointInside:withEvent:对于视图A返回YES ,因此在视图B和视图C上调用pointInside:withEvent:。视图B返回NO 。 视图C返回YES,因此将其调用hitTest:withEvent:。 视图C与视图D和视图E遵循相同的过程。视图D在pointInside:withEvent:上返回NO 。 视图E返回YES ,然后在hitTest:withEvent:上返回自身,因为它没有任何子视图。 假设视图D是视图C的子视图,那么如果用户在视图D超出视图C的范围内点击,会发生什么? (当clipsToBounds为NO时,可能会发生这种情况。)视图A启动上述过程。 视图B和视图C的pointInside:withEvent:均返回NO ,因此视图A最终获得了触摸。 现在,我们有了hitTest:withEvent:的视图。 该视图称为“命中测试”视图。 现在,它与触摸相关联,在触摸处于活动状态时,将获得第一个机会以响应任何触摸事件(稍后会详细介绍)。 如果没有针对给定触摸的自定义实现,会发生什么? 这取决于。 如果视图是由视图控制器管理的,则视图控制器将有机会做出响应。 如果该视图控制器没有响应,则为命中测试视图的超级视图提供响应的机会。 一直重复此过程,直到称为“响应者链”为止。 响应者链 响应者链是责任链设计模式的一种实现。 响应者链中的每个参与者都继承自UIResponder。 UIResponder包含处理各种类型事件的离散方法。 除了触摸事件外,UIResponder还声明用于处理输入视图,运动事件,按下事件和远程控制事件的方法。 对于许多此类事件, firstResponder很重要。 firstResponder是第一个获得处理事件机会的对象。 […]

持续的iOS学习-第1部分(文章)

我想与大家分享我所订阅的网站,博客和新闻通讯 ,每天我都会学到有关iOS , watchOS , tvOS和OS X应用开发的新知识。 随意添加自己喜欢的。 http://swiftsandbox.io http://www.cimgf.com http://ios-goodies.com http://en.swifter.tips https://littlebitesofcocoa.com https://iosdev.tools https://www.natashatherobot.com http://appcoda.com http://iosdevweekly.com https://www.objc.io http://swiftdevweekly.co http://realm.io http://useyourloaf.com http://nshipster.com http://nsscreencast.com http://www.pomo.tv http://www.cocoawithlove.com https://www.skilled.io https://www.weheartswift.com http://www.sososwift.com https://www.mikeash.com/pyblog/ http://swiftdeveloperblog.com http://jamesonquave.com http://www.learnswift.tips

Ruby数值类型:是和不是

在大多数编程语言中,我们拥有各种数字类型。 Ruby为我们提供了5种不同的选择: 固定编号 比格纳姆 合理的 浮动 大十进制 为什么? 作为世界上的所有事物,我们通常根据其特征将数字分为不同的集合。 最常见的-可能是您在开发软件时接触的所有对象-以下是: 自然数 , 整数 , 有理数和无理数 。 整数 自然数是指以1开头并保持加1的自然数。因此,1、2、3、4、5,…。 整数是相同的数字,但也包括相反方向的相同求和,即0,-1,-2,-3,-4,…。 Ruby对此集合有一个表示形式:抽象类Integer。 它的具体兄弟是Fixnum和Bignum。 > 10.class => Fixnum 当您将Integer文字(看起来像Integer的东西)提供给解释器时,该语言将尝试将其适合Fixnum实例。 但是有时候这不可能发生。 我们有内存限制,因为Ruby不允许Fixnum大于本地机器字[1](这在处理器之间会有所不同)。 >整数= 2 **(1.size * 8-2)-1 => 4611686018427387903 > integer.class => Fixnum >整数=(整数+ 1).class => Bignum >(-整数-2).class => Bignum 处理大于四百亿个基数的数字不是日常工作,因此使用Fixnum应该没问题。 如果将变量的值更改为超出支持范围(大于或小于)的数字,Ruby将负责释放用于保存该值的内存并将其存储在其他位置。 最后一个将被视为无限分配,因此您可以将其用于基本上可以得出的任何整数。 [1]:Ruby核心团队已经在努力定义一种更简单的方法来获取适合Fixnum对象的最大和最小数量。 看一看: https : //bugs.ruby-lang.org/issues/7517 做和不做 […]

快速提示:基于闭包的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开发提示和技巧

当您销售长期开发的应用程序的时候到了,或者您即将接管一个应用程序时,您可能不必担心过渡过程。 尽管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

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中加载任何自定义内容了!

在C,Go和Swift中构建小型跨平台CLI工具

这就是我写一个简单工具的方式。3次,用不同的语言。 本实验 我的目标是编写一个非常简单的命令行工具,该工具可以生成与Google Authenticator兼容的一次性密码。 Google身份验证器使用基于时间的一次性密码算法(TOTP)生成代码。 我不想使用自己的实现,而是想使用现有的TOTP库,因为已经有很多不错的库。 本质上,我要我的工具要做的就是接受一个秘密作为单个输入,然后调用现有的TOTP库生成代码,并将生成的访问代码打印到标准输出中。 我问自己的问题是:假设我想在多个平台(Mac,Windows,Ubuntu)上使用该工具,并且希望 在少数人(不一定是技术人员)(例如同事)中分配工具,哪种编程语言将是最实用/可行/有趣的选择? 当然,您可以从多个角度看待这个问题。 让我们专注于构建和分发工具。 然后,这些是我的“应有”要求: 应该有可能将工具分发为“开箱即用”的单个可执行文件,这意味着用户不必安装运行时,框架,库等依赖项。 使用相同的代码库(但可能使用不同的工具链),应该可以为多个平台生成构建。 语言选择 我想为这个特定的实验创建一个二进制文件,这就是为什么我没有为此特定工具考虑诸如Node.js,Ruby和Python之类的解释语言的原因。 当然,尽管总的来说,这些语言都能为编写跨平台命令行工具提供完全可行的选择。 这些语言还有一个缺点,那就是最终用户需要安装运行时(例如Node.js)。 尽管许多平台都预先安装了常见的运行时,但是用户可能需要安装其他版本。 对于非技术用户而言,这并不总是一件琐碎的任务。 (我知道有一些工具可以将解释后的语言编译为独立的可执行文件,但这有点像在作弊) 。 最后,我的选择是尝试使用C , Go和Swift 。 我决定留在“编程语言舒适区”,因为学习一种新语言不是我实验的一部分。 因此,我没有尝试过(很有用)非常有趣的其他语言,例如Rust ,我将在以后尝试 (随时对您的Rust经验发表评论)。 也许还需要注意:在本实验中,我考虑了C ++的过大杀伤力(或者实际上,我的C ++ 只是缺乏知识)。 我学到的是 C 通常,使用C构建的可执行文件是动态链接的。 这意味着最终用户需要安装依赖项(链接的库)才能运行该工具。 那绝对不是理想的。 有很多解决方法,但是所有这些都有一些缺点: – 静态链接:创建单个二进制文件,其中将包含所有必需的二进制代码。 但是,这要求您使用的所有库(例如TOTP库)都支持静态链接。 绝对不是总是这样。 此外,Apple在Mac OS X上不支持静态链接的二进制文件。 – 将链接的动态库与您的应用程序一起分发 。 这意味着对于每个目标操作系统,您都必须预先构建所有链接的库,请确保可执行文件可以找到这些库(例如,在macOS上更改rpath),并将其与应用程序捆绑在一起。 换句话说,您需要将.dll (Windows) .dylib (macOS)或.so […]

每个iOS应用程序都必须具备应用程序安全性

应用程序安全性是软件开发最重要的方面之一。 我们应用的用户希望他们的信息被保密。 我们的敏感应用程序数据不应简单地泄露出去。 幸运的是,在本文中,我们将讨论开发人员在应用安全性方面所犯的错误以及如何轻松修复它们。 将敏感数据存储在错误的位置 我从AppStore研究了多个应用程序,其中许多应用程序都在犯同样的错误,将敏感数据存储在不属于它们的地方。 如果要将敏感数据存储在UserDefaults ,则可能会UserDefaults应用程序信息的风险。 UserDefaults只是作为属性列表文件存储,位于应用程序的Preferences文件夹中。 它们会保存在我们的应用中,而不会以任何形式进行加密。 基本上,通过使用示例中的iMaczing这样的第三方mac应用程序,甚至无需越狱设备,您就可以轻松查看从AppStore下载的任何应用程序的UserDefaults数据。 这些Mac应用程序经过专门设计,可让您浏览和管理iPhone上的第三方应用程序文件。 而且,您可以轻松浏览任何应用程序的UserDefaults 。 促使我写这篇文章的原因是,我发现从AppStore安装的许多应用程序都将其敏感数据写在User Defaults上。 例如访问令牌,活动可更新订阅标志,可用硬币数量等。 从免费使用付费功能到入侵网络层等等,所有这些数据都可以轻松检索和更改,并损坏应用程序。 正确的做法 在iOS应用程序上保存数据时,请始终牢记一件事, UserDefaults旨在仅保存少量数据,例如应用程序内用户的首选项,这是完全不敏感的。 为了保存我们的应用程序敏感数据,我们应使用Apple提供的安全服务。 钥匙串服务API通过为您的应用提供一种将少量用户数据存储在称为钥匙串的加密数据库中的方法,可以帮助您解决这些问题。 在钥匙串中,您可以自由保存用户明确关心的密码和其他机密信息,例如信用卡信息,甚至是简短的敏感便笺。 您还可以存储由证书,密钥和信任服务管理的项目,例如加密密钥和证书。 钥匙串服务API 下面我们将描述如何在钥匙串中保存用户密码。 查询字典部分kSecClass:kSecClassGenericPassword指示该项目是密码,钥匙串服务可从中了解数据需要加密。 然后,通过使用创建的查询调用SecItemAdd ,将新密码添加到钥匙串中。 检索数据类似 我们可以编写一个简单的测试来确保正确保存和检索数据 如果您必须保存多个密码,一开始使用Keychain API似乎有点复杂。我鼓励您为其创建外观,以帮助您根据应用程序使用情况以最佳方式保存和修改数据。 如果您想进一步了解外观模式以及如何为复杂的子系统创建简单的包装器,那么本文将对您有很大帮助。 另外,有许多开源库使Keychain API的使用更加简单。 其中一些是SAMKeychain和SwiftKeychainWrapper。 保存密码并执行身份验证 在我作为iOS开发人员的职业生涯中,我看到相同的错误不断重复出现。 很多时候,开发人员要么将原始密码保存在应用程序中以重复使用,要么直接使用用户名和密码发出登录网络请求。 如果您将密码直接存储在UserDefault那么现在应该知道本文第一部分提供的信息UserDefault您造成多少风险。 将密码保存到钥匙串可以提高安全性,但是,再次,我们应该始终通过初始加密将密码和其他敏感信息保存到钥匙串或其他地方。 假设攻击者可以通过钥匙串安全性进行黑客攻击或通过我们的网络进行攻击,从那里他可以直接以原始文本的形式检索我们的密码。 更好的方法是存储密码,并将其用于登录请求,作为为此密码构建的哈希。 加密敏感数据 自己实现散列可能非常复杂且过大,因此在本文中,我们将使用开源iOS库CryptoSwift的帮助。 CryptoSwift是在Swift中实现的标准安全加密算法的不断增长的集合。 让我们尝试使用CryptoSwift提供的算法在钥匙串上保存和检索密码。 此方法使用帐户和密码,并将散列的字符串而不是直接字符串保存在钥匙串上。 让我们分解一下这种方法正在发生的事情 salt是用于混合密码的唯一字符串。 sha256完成类型SHA-2哈希 HKDF是基于基于哈希的消息认证码(HMAC)的简单密钥派生功能(KDF) 我们制造盐以使我们更容易受到攻击。 […]

iOS和模板Haskell

与Android和Haskell模板类似,我们需要将GHCSlave(远程iserv)实例包装到iOS应用程序中。 在iOS设备上提供Template Haskell评估上下文。 从昨天开始使用适用于iOS的Haskell Cross Compiler,我们现在将构建GHCSlave iOS应用程序。 警告:由于x86_64链接器代码中的错误,Template Haskell尚不能与iOS Simulator一起使用。 链接器代码固定后,我已用斜体标记了模拟器的命令,并将删除此警告。 在此之前,模板Haskell只能在设备上/在设备上使用。 先决条件 同样,我们需要构建iserv-proxy和iserv库。 如果不清楚, 请参考 Raspberry Pi的 说明。 签出自定义ghc分支后: git clone-递归git://git.haskell.org/ghc.git 光盘ghc git remote add zw3rk https://github.com/zw3rk/ghc.git git fetch zw3rk git checkout -b zw3rk / my-ghc git reset –hard zw3rk/my-ghc git子模块更新–init –recursive 我们需要使用我们的常规编译器来构建iserv-proxy : ghc / iserv $ cabal install -flibrary -fproxy 以及带有交叉编译器的iserv库: ghc […]

在下一个项目之前,请学习MVVM

我不是iOS开发专家。 经过一个月的学习,我最近开始在Swift中为多个行业开发应用程序。 我确实喜欢每个初学者,并打开了Apple文档,并遵循了他们的指南。 苹果公司推荐的模式是MVC模式。 我按照大家都知道并珍惜的Model View Controller的经典原理开始构建自己的第一个应用程序。 从表面上看,iOS开发中的MVC模型与我们多年来使用的模型没有什么不同。 对我来说不幸的是,我一直对软件体系结构,简洁的代码和漂亮的软件感兴趣,因此将iOS和MVC结合使用非常麻烦。 几周后,随着视觉和幕后应用程序变得越来越复杂,问题就显而易见了。 在为iOS开发时,您的视图(也称为Storyboard)是一个简单的XML文件,其中包含所有不同的组件以及它们的坐标和约束。 这样做的结果是,与实例的实际功能相比,负责实例化和管理这些视图的ViewController文件变得混乱而庞大。 您开始在同一类中查看混合在一起的不同关注点:路由,模型处理,动画,视图填充…都在一起💀。 这种使用起来令人困惑和痛苦的方法,通常被称为Massive View Controller综合症。 于是去寻找其他选项,然后在此处输入MVVM 。 MVVM模式或模型视图ViewModel围绕应将模型处理和视图处理分开的想法而展开。 这样可以实现更好的可测试性,可读性并易于开发。 为此,我们将ViewController分为二。 View (仍然继承自Apple ViewController类)将填充视图并管理动画。 屏幕上显示的所有内容均受其控制。 ViewModel负责与API,数据库和其他信息源进行交互,并提取与其相应视图有关的信息。 实例化视图时, View将自身绑定到其ViewModel并将根据ViewModel提供的数据进行更新。 有多种方法可以实现这一点,但是Swift提供的我的首选方法是通过闭包。 为了说明这一点,让我们想象一个打印当前日期的愚蠢视图。 我们可以从设计ViewModel开始: 简单的ViewModel示例 这里, ViewModel公开了一个变量和一种方法。 fetchDate()方法将获取当前日期并为其分配一个私有变量。 每次设置此变量时,都会调用一个可选的公共方法updateDate 。 此方法是一个公共变量,可以通过View设置这样的方法: 简单检视 实例化ViewModel , View会将其闭包简单地附加到其ViewModel的公开变量,然后触发获取。 如果需要,setupView方法将使用初始内容填充视图。 当获取成功完成并且在fetchDateFromApi函数上updateDateClosure了回调时,将updateDateClosure并更新标签。 所有这些异步且易于维护。 唯一令我烦恼的是, View仍然必须通过prepareForSegue和其他方法来处理路由。 在实现表示和模型处理之间的清晰分离之后,我们不能简单地乐于在这种情况下进行路由。 为了解决这个问题,我创建了一个简单的路由器协议(与旧接口的Swift等效): 基本但清晰的路由器实现 viewController的init方法是一种便捷的init方法,无需查找相应的Storyboard 。 枚举和协议只是为了清楚起见。 但这使我们可以在文件中简单引用此路由器: 将路由器添加到先前的类中 […]