每个iOS应用程序都有一个关联的容器,作为开发人员,您可以在其中基本上存储所需的任何内容。 这通常称为“沙盒”。 在此沙箱中,您可以放置用于不同目的的文件-它可以是用户可见的文档,数据库文件,缓存或某种元数据-任何东西。 基本上,iOS上的所有持久性技术都使用应用程序的容器在其中存储信息。 因此,了解应用程序文件夹的外观,结构以及放置在其中的文件对于每个iOS开发人员都是至关重要的。 但是,这里存在问题: 不幸的是,对于每个iOS应用程序都至关重要的概念,Apple并未对其API进行过多考虑 因此,例如,如果您需要获取应用程序的“ Documents”文件夹URL,则需要编写以下代码: let urls = FileManager.default.urls(for:.documentDirectory,in:.userDomainMask) 让documentsURL = urls [0] 如果您确切知道该代码在做什么,那可能看起来还不错。 但是对于不习惯此API的人来说,它看起来也很恐怖。 因为当您尝试使用自动完成功能来发现您的选项时,会得到以下信息: 在这种情况下,有人会怀疑“这里到底发生了什么?”。 .adminApplicationDirectory ? .applicationScriptsDirectory ? .moviesDirectory , .trashDirectory吗? 有很多东西,其中大多数对于iOS应用程序绝对没有任何意义 。 然后是搜索路径域掩码: …嗯, 是的,我确切知道该选择哪一个。 这个API对于macOS可以说是合理的,但是在iOS上,这显然是令人误解的: cachesDirectory放置在musicDirectory和desktopDirectory (显然,这不仅对每个设备而言都是唯一的,而且对于iOS而言也是荒谬的)。 由于某种原因,“ Documents / ”目录表示为.documentDirectory (单数),这可能使您质疑是否选择了正确的文件夹。 它返回一个URL 数组 (可以有多个URL吗?可以没有一个吗?谁知道。) 最后,使用此API,您几乎不了解文件夹在磁盘上的实际结构。 尚不清楚此巨型列表中的哪个文件夹甚至存在,哪些不存在。 我们可以做得更好 好吧,想象一下我们是否可以交易上面的代码 let urls = FileManager.default.urls(for:.documentDirectory,in:.userDomainMask) 让documentsURL = urls […]
NSNotificationCenter可以被视为在您的应用程序中传达信息的工具。 与推送通知或本地通知不同,在这些通知中,您会通知用户您希望他们接收的任何内容,NSNotificationCenter允许我们根据应用程序中发生的操作在类和/或结构之间发送和接收信息。 简而言之,可以将NSNotificationCenter视为广播公司,我们可以收听不同的电台或频道以收听任何更改。 NotificationCenter.default是所有通知发布和观察对象的位置。 每个通知都必须具有一种独特的方式来标识自己,如果继续进行类比,则该方式将代表我们要进入的频道。 同样,如果我们要观察或收听任何频道,则可以通过NotificationCenter.default调用对我们可用的观察方法,并基于此侦听执行某种类型的操作。 我创建了一个简单的应用程序,该应用程序演示了NSNotifcationCenter的用法,以便我们可以更好地理解代码中的形式以及它的实际工作方式。 如果您像我一样,并且是动手学习者,请随时进行编码。 在此应用程序中,我嵌入了导航控制器,并连接了所需的所有IBOutlet和IBAction。 该应用程序的目标是显示从其他视图控制器中选择的目的地的名称。 首先,我们将创建在NotificationCenter在给定通道中检测到更改时将执行的操作。 在我们的案例中,我们正在创建两个函数,这些函数将更改ChoiceDestinationVC中的城市标签。 func setToPeru(notification:NSNotification){ cityChosenLabel.text =“秘鲁” } func setToArgentina(notfication:NSNotification){ cityChosenLabel.text =“阿根廷” } 每个函数都会将cityChosenLabel设置cityChosenLabel相应的文本。 我们将不会对这些功能做任何事情,但是很快,当我们开始在应用程序中进行观察时,我们将对其进行调用。 还记得我提到每个通知应具有唯一身份吗? 好了,我在Notification.Name上创建了一个扩展,并在每个通道的名称上添加了两个静态属性。 通常,您可以手动键入包含您要在调用observe或post方法时用于通知的名称的字符串,但这可以帮助我们避免错误,并减少因拼写错误而导致错误的空间。 扩展Notification.Name { 静态让秘鲁= Notification.Name(“秘鲁”) 静态让阿根廷= Notification.Name(“阿根廷”) } 之后,我们将在ViewDidLoad中添加观察方法,这些方法将侦听其指定的通道并根据每个通道执行操作。 NotificationCenter.default.addObserver(自身,选择器:#selector(setToPeru(notification :)),名称:.peru,对象:无) NotificationCenter.default.addObserver(自身,选择器:#selector(setToArgentina(notfication :)),名称:.argentina,对象:nil) 我们的第一个观察者方法将执行我们上面创建的功能setToPeru(notification:) ,如果通知已发布到.peru通道,我们将在其中更改标签的文本。 然后将相同的内容应用于侦听并将标签文本更改为阿根廷的setToArgentina(notification:) 。 从这里开始,我们进入下一个视图控制器DestinationVC。 当有人单击任一按钮时,我们将在此处发布通知。 @IBAction func peruButton(_ sender:Any){ NotificationCenter.default.post(名称:.peru,对象:无) } @IBAction func argentinaButton(_ sender:Any){ […]
硬编码字符串很麻烦,编译器无法检测到错字,而且重命名也成为问题。 为了解决此问题,我使用了shell脚本来自动生成文件,这有助于为代码添加约定并确保这些硬编码字符串的安全性。 如果您不清楚添加运行脚本的基本步骤,请阅读此处。 请执行以下步骤: 在项目的“ Target Dependencies”下添加运行脚本,然后输入以下代码行: #所有要执行的运行脚本必须在mainScript.sh中键入,不要在此处写任何内容 $ SRCROOT / shellScriptStringGeneration / Build-phase / mainScript.sh 2.从附加的github项目 —将构建阶段目录复制到您的项目 —使用终端“ chmod u + x mainScript.sh”添加执行权限 —从所有shell脚本中删除“目标成员身份” 3.现在创建空的Constants.swift / Constants.images.swift / Constants.storyboards.swift /添加到您的项目中 4.在每个shell脚本中,更新输入路径,如下图所示
大家好,欢迎来到本系列文章的第二部分,我将向您展示如何在Swift上重写Todo Rugby。 在第一部分中,我向您展示了如何使用Drawer,Tab和NavigationManager以编程方式构建骨架。 在这一节中,我将介绍以下几点: 联网:使用Moya编写服务层,以及全新的Codable协议,这是Swift 4的一个很酷的功能。 基类:为什么要考虑使用它们。 平等:如何以Swift方式实现旧的isEqual 。 guard let :您的所有可选问题的战刀。 莫亚 网络层是处理API数据的任何应用程序中非常重要的一部分。 阅读并研究了可用的最佳工具和Pod之后,我介绍了Moya,这是一个网络抽象层,其内部使用Alamofire(Swift AFNetworking的继承者)。 该框架的有趣之处之一是,您不必在每次启动新应用时都重写新的网络客户端。 它在内部处理。 您必须指定的唯一内容是: 枚举:您的所有请求都将在枚举中定义,包括其参数和其他数据。 基本网址:用于访问您的API的网址。 端点:对于每个新的枚举,您必须告诉他们哪个是该枚举的关联端点,以及它应如何处理该端点上的参数。 方法:应该为每个枚举值( .get , .post等)使用的HTTP动词。 任务:请求应为纯请求还是具有其他数据(查询字符串参数,表单数据,多部分等)。 标头:您应为每个端点使用哪些标头。 样本数据:是的,因此,如果您提供端点,则可以模拟端点。 在使用“抽屉”和“选项卡”设置导航之前,我一直喜欢做的事情是控制更新,以及是否应强制执行该更新。 也就是说,如果用户仍然可以使用与更新有关的应用程序,或者唯一的使用方式是通过更新来使用它。 我没有介绍如何编写您的强制更新逻辑,但是我要介绍的第一个端点是version 1。 在实现符合TargetType协议的Service枚举后,您应该具有以下内容: 有关JSONDecoder类如何处理结构及其键的更多信息,请从第24分钟开始观看此视频。 继承是OOP的强大工具,您应该始终尝试利用它。 在iOS(在本例中为Swift)上,我喜欢以下基类: BaseViewController 它继承自UIViewController并具有方便的方法来处理NavBar设置,屏幕跟踪以及更多其他功能。 BaseTableViewCell 可以想象,它继承自UITableViewCell并具有非常有用的方法。 它还具有一个model属性,该属性是实现Decodable协议的结构。 看起来像这样: 可能您从未实现过isEqual方法。 我认为其原因之一是因为它花费了大量代码: isEqualToTournament是一个方便的方法,例如isEqualToString或isEqualToNumber ,因为知道接收者来自同一类,所以您可能会使用此方法。 但是,如果要对列表进行排序或使用在isEqual使用isEqual集合进行操作,则必须实现它。 使用Swift,我们有一个了不起的功能,称为运算符重载(如果您使用C ++编写代码,您可能知道我在说什么)。 基本上,您可以覆盖运算符以对对象执行自定义操作。 在这种情况下,我们将覆盖==运算符,以便可以使用它检查两个对象是否相等: 惊人! 现在,每次您在两个锦标赛之间编写==比较时,它将使用此运算符并在内部检查其ID。 我要在这篇文章上谈论的最后一件事是关于尽早返回的一种编码样式,该样式检查并返回无效的情况,并使您专注于实际上将在您的方法上执行的代码。 […]
好吧, 真的是一个小案例。 如果您要在上面烤我… 通过一系列不幸的事件,我最近意识到Swift的默认排序算法可能会产生不稳定的结果。 这不仅让我感到沮丧,而且令我非常恼火,即使从Swift 3开始 ,也没有默认的稳定类别可以使我们的生活更轻松。 通常,这样的事情不会打扰我。 实际上,在大多数情况下,我可能不太在乎这些事情。 但是,在这一特定的日子,这使我非常困扰。 时间压力和使数据排列不正确的费用高得离谱,这使我不得不迅速解决这个问题。 现在,我将假设许多阅读本文的人对“稳定”排序的含义没有丝毫的了解。 因此,我将以我理解的方式在下面进行说明: 仅当两个相等的待排序对象被算法单独处理时,排序才被认为是稳定的。 确实,开发人员只应关心排序列表的稳定性,前提是这样做的代价是不小的 。 老实说,我对自己感到有些失望。 我天真地认为sort()对于我们所有的用例都可以完美地工作,并且我不需要对数据排序进行过多的关注。 假设是“所有操蛋之母”。 分类问题与山丘一样古老。 它们非常普遍,甚至可能导致代码中似乎无法完全解决的错误。 如果您使用Swift的时间超过大约四秒钟,那么您可能在Swift代码中使用了sort()几次。 您是否对潜在的边缘案例足够重视? 在与我的团队讨论了四个字母并进行了“您为什么认为此错误发生的原因”的讨论之后,粗略浏览一下sort()的快速帮助面板会向我们发出警告,指出不稳定算法最有可能是我的问题的原因。 经过快速检查,我们一起证明了。 为什么要为我们吸? 我们碰巧正在使用的应用程序在很大程度上依赖于向客户提供准确的数据。 基本上,用户可以订阅服务,并且每月向他们收费,这些订阅也可以停止。 每当我们去查询用户的订阅历史列表时,这个问题就变得很丑陋。 我们希望对数据进行排序,以便将给定订阅的历史记录和父列表本身从最旧到最新进行排序。 由于后端仅知道的原因,订阅的状态会在99.999%的时间内明显地发生变化,例如,从“ 请求”变为“活动”到“ 已停止 ”。 但是,在最小的0.001%的时间内,状态将立即更改。 问题就出在这里。 因为我是按日期排序的,所以列表最终混乱了,因为其中的某些项目被认为是相等的,并且Swift的排序算法不稳定。 我的解决方案 现在,虽然我可能已经能够为sort()提供更多指标, 我选择立即使用更强力的解决方案。 由于Swift对我来说还是很新的东西,因此我选择了老旧的Objective-C解决方案。 让sortedArray =(parentList as NSArray).sortedArrayWithOptions(.Stable,usingComparator:({(lhs,rhs)-> NSComparisonResult在 let lhs =(lhs as!Record)//用您的数据类型替换 let rhs =(rhs as!Record)//与上面相同 如果lhs.date […]
考虑一下协议。 我们在应用程序中广泛使用它们来委派操作,支持多重继承概念并在引用和值类型上创建复合功能。 更进一步,我们可以通过使类和类型定义符合协议来扩展它们。 我们可以定义协议类型变量并使我们的类型更灵活(不包括关联类型和自我需求协议)。 每个(不透明的)容器在内存中都有3个部分: 三个存储字的长度缓冲区,用于保存Value :如果值的大小大于3个字,则将其存储在堆中,并且地址保存在此处。 MemoryLayout.size(ofValue:alice)// 32字节 //因此将其存储在堆中,并将其地址保存在值缓冲区中 一个记忆词表示“ 元数据 ” 每种协议类型都有一个存储字,用于存储“ 协议见证表 ” 。 如果您的变量由N个不同的协议组成,则将其计算为N个存储字。 对于* protocol的声明*中的每个方法,都有一个指向其符合类型的实现的指针。 因此,当您在协议扩展中定义一个方法时,该方法将不会出现在见证表中,并且在您的变量上使用该方法时,它会被静态分派,并返回其默认实现,如上面的示例。 如果您想要重写的实现,则只需将其添加到协议声明部分,即可按预期工作😊
在返回语句之后,Swift将执行一个返回Void的函数,然后退出该函数。 在上面的示例中,由于打印函数返回Void,它将在退出myFunction之前执行。 此行为可能与其他控制语句(如guard)结合使用。 守卫的例子 但是, defer语句仍然在最后执行。 延迟示例 下面是一些其他带有(…)-> Void签名的愚蠢函数。 更多例子
毎ル日自体は日本语で书きますが,海外记事の绍介も织り交ぜていく予定です。毎周日〜月曜日あたりに配信目标で,无理そうなら隔周や毎月あたりに频度下げるかもしれません。 ちなみに,海外のSwift ・ iOSメルマガはこのあたり购読・爱読しています。 适用于iOS和OSX的免费每周Swift开发时事通讯 代码示例,教程,屏幕录像以及更多内容可用于学习Apple的新编程语言Swift。 订阅… www.swiftweekly.com 斯威夫特本周 嗨,我是@NatashaTheRobot,我被编程为喜欢#Swift! 每周,我都会整理出最好的Swift列表… swiftnews.curated.co iOS Dev Weekly –每个星期五的最佳iOS开发链接 每周订阅精选的最佳iOS开发链接摘要。 由Dave Verwer策划并出版… iosdevweekly.com 迅捷月刊 #Swift每月通讯,其中包括:精选的Swift教程,新闻,视频,工作,会议以及更多交付的东西…… swiftmonthly.com 迅捷周刊 关于Swift.org的社区驱动的每周新闻 swiftweekly.github.io 以下の记事などでも,メルマガ重宝しているということを绍介しています。 Google收件箱,GitHub,Slackと肩を并べるくらい使うようになったので使いこなし术を绍介– Qiita 最近,GoogleのメールWebアプリ收件箱を,开発周りの情报や通知を受け取ったり管理ったりールとして,かなり重宝しています。今年の5月に一般公开されてから,邮箱系のメールアプリとして绍介される记事はちょくちょく见か… qiita.com iOSアプリ开発情报の集め方– Qiita たまに,どこから情报收集しているんですか?と闻かれるのでまとめてみました(・‿・`)今は玩家! qiita.com 良さげなiOSライブラリの见つけ方・管理法– Qiita 降临日历に空きがあって完走の危机だったので今年でSwift关连连の良记事7选– Qiitaと同じく,良さげなiOSライブラリの见つけ方・管理法を振り返りました。やはり良い感じのライブラリを把握しておくのは,… qiita.com 読んでくださる方にとって有用な情报となるようにしたいですし,自分本身の有用记事本としても活用していきたいと思っています(・‿・`)
当我们谈论有关iOS应用程序的安全性时,我们通常会考虑诸如SSL证书,将信息安全地存储在钥匙串中之类的事情。 这一切都很好,而且我们现在如此广泛地关注是一件非常了不起的事情。 但是,有一个小的罪魁祸首是许多应用程序制造商似乎忽略了,我不怪他们。 我说的是操作系统内置的多任务处理功能。 那么,是什么使它成为罪魁祸首? 好吧,基本上,如果用户决定退出您的应用程序,则操作系统将为当前视图控制器的当前状态制作快照,并将其保存为应用程序的占位符。 但是,如果您刚离开的屏幕上有一些您不想离开应用程序的个人信息,该怎么办。 也许您正在使用银行应用程序,而同事或朋友借用您的电话,则他或他将能够阅读您上次使用该应用程序查看的部分信息。 听起来好像我过度夸大或出于非问题而提出了问题。 也许吧,也许不是。 我所知道的是,如果我使用存储个人或敏感信息的应用程序,则希望它保留在该应用程序内,而不会以任何方式,形状或形式泄漏。 因此,这就是我们为应用程序增加一些额外安全性所做的工作。 因为我们不确切知道哪个屏幕应该安全或哪个屏幕可以显示,所以我们采取了尝试保护整个应用程序的路径。 这就是我们所做的。 在构建iOS应用程序时,您需要提供一个应用程序委托。 此类具有在我们的应用程序的上下文更改时被调用的方法。 我们将使用应用程序委托监听的两种情况是: func applicationDidBecomeActive( _ application:UIApplication) func applicationWillResignActive( _ application:UIApplication) 您可能已经知道很多,即使您不知道。 您可能会猜测何时调用这些方法。 当我们的应用程序变为活动状态时,第一个被调用,而当用户离开我们的应用程序时,第二个将被调用。 因此,为了增加一点安全性,我们将使用模糊的视图简单地覆盖当前窗口,以免撬开的眼睛看不到屏幕上正在显示的内容。 使用模糊功能不是最安全的选择,但是暂时,我们只希望在有人借用电话时将可以直接访问电话的人拒之门外。 如果需要更高的安全性,则可以显示应用程序启动屏幕或猫的图片。 由你决定。 聊够了,让我们看一下代码。 请记住,仅添加一点点的安全性是不够的,您可能想要添加一个密码屏幕并执行通常执行的所有其他与安全性相关的任务。 这只是为了防止您的应用向iOS上的多任务功能泄漏信息。
为什么要开发此脚本 当我们在iOS领域中开发一些Pod组件时,我们必须在终端上键入那么多git和pod命令。 如果Pod项目很大,并且运行pod lib lint和pod repo push将花费大量时间,则还必须更新.podspec文件和push标签中的pod版本。 这是一个非常无聊且机械化的过程。 该脚本将使您摆脱此过程。 该脚本包含哪些操作 1.在.podspec文件中制作小版本加一个,例如,将s.version = “0.1.1”更改为s.version = “0.1.2”或将s.version = “1.2.15”更改为s.version = “1.2.16”或s.version = “10.22.0.15”到s.version = “10.22.0.16” ,无论您的版本是什么样,它都会更新版本号的最后一位。 2.运行pod lib lint 。 如果您的Pod项目依赖于其他私有资源,则可以在脚本顶部对其进行配置。 在Github和GitLab上运行良好。 至于BitBucket,您可以尝试一下。 如果您发现它不起作用,请让我知道。 3.运行一系列git操作,例如git add,git commit,git push,git tag,git push-标签。 4.运行pod repo push 使用情况 1.将auto.py添加到您的pod项目中,并确保它与.podspec文件位于同一目录中。 如果您认为有必要,可以将此python脚本文件添加到.gitignore 。 2.打开auto.py文件,并在顶部对其进行配置。 像这样的截图 您可以在sources数组中添加从属源,但是不需要添加https://github.com/CocoaPods/Specs.git 。 3.打开终端,导航到poedspec和此脚本文件所在的目录。 4.在终端上运行python auto.py命令。 它会自动更新您的Pod项目版本并将其自动推送到原始位置。 如果失败,则必须检查并确保您的podspec配置正确。 下载 […]