Tag: 可可

Mac开发人员提示:共享扩展中的NSTouchBar

您正在使用支持MacBook Pro的Touch Bar的Share扩展程序,但是它为空并且在加载扩展程序时没有出现? 解决方案很简单: 调用[self.view.window makeFirstResponder:self.view]; 它将把您光荣的NSTouchBar推入堆栈: 希望能有所帮助-如果我知道known,它将为我节省20分钟

项目6.7 –笔记薄弱的一周

沉默接管了项目6。6.3和6.4是周末在电脑上度过的时间,由于缺乏进度,6.5和6.6被迫放弃了说话。 将我们最终安静地带到6.7-6周计划的一个星期。 我一直在研究可可,NS前缀和苹果不太喜欢的开发套件的来龙去脉。 我的意思是没有冒犯,Mac应用程序可以很漂亮而且令人惊叹,只需询问Panic,但是您只能看到很多次 不会因CocoaTouch的普遍存在而感到孤独。 凭借多年的Apple开发人员经验,我觉得自己的工作效率只有一半。 每个Autolayout错误,以及解决了您从2002年以来的问题的方法的文章都不再起作用,并且坐标系的完全怪异意味着调试和测试比运送要花费更多的时间。 一个例子就是希望在NSTextView中找到光标的位置。 经过大量的UITextView答案,我找到了可能的解决方案。 textView.firstRect(forCharacterRange:,actualRange:) 这是为了给我当前选定范围内光标位置的NsRect。 只要您喜欢绝对的屏幕坐标,一切都会很好,但是对我来说完全没用。 该兔子洞进展为尝试使用以下命令将窗口坐标映射到文本视图的原点 [textView convertRect:rect fromView:textView.textInputView] 但是由于某种原因,textView的原点返回0,0,并且每个Stack Overflow都带来了比以前更多的问题。 最后,我浏览了足够多的NSContainers和NSLayoutManager文档,以偶然发现圣杯 让cursorPoint = textView.layoutManager?.boundingRect(forGlyphRange:textView.selectedRange(),在:textView.textContainer!) 最后,我兴高采烈地出现了,只花了一个小时就在光标位置插入了一个子视图。 (#ForFutureGoogle在NSTextView中找到光标/插入符号的局部坐标)。 然后,此模式进行多次自我复制,分为多个Objective-C至Swift复制粘贴重构以及Swift 2至Swift 3弃用路径。 我喜欢Swift作为一种语言,在搜索iOS解决方案时并没有这么大的问题,所以我的猜测是iOS内容更新速度更快并且紧贴前沿,或者iOS内容庞大而过时搜索。 就是说,总共大约20个小时之后,我已经成功地使用本地数据库,一个很酷的Medium风格的插入菜单和Operational Transformations构建了一个本地Notes应用程序。 回想起来,也许启动了一个未知数众多的项目,尤其是在第一周就显得有些雄心勃勃。 此外,我希望在该应用程序上花费总计超过20个小时,因此我认为最终产品将更加精美。 此外,我花了几个小时将一些逻辑提取到一个单独的库中,以用于业务逻辑/操作转换逻辑(以防我想创建一个iOS应用程序)和另一个库,用于包装类来处理中型TextView。 尽管如此,到最后,我还是学到了很多新的Cocoa开发人员,对任何Mac App开发人员都产生了新的尊重,并非常喜欢这个项目。 下一步? 我想花更多时间将应用程序完善成可用的工具,也许还要研究一下iOS应用程序和CloudKit的集成。 长期-如果我无法或不会支持我,我可能会愿意公开采购整个应用程序或库组件。 如果有人对应用程序感兴趣,或者代码可以随时与我们联系,那肯定会帮助我评估这些选项。 今天花费的时间:4小时 总开发时间:〜20小时 结果:工作记录应用 任务完成1/6 还是足够接近

隐藏窗口,而不是单击关闭按钮时将其关闭

开发单个窗口式,非基于文档的Cocoa应用程序时出现问题。 也就是说,当用户单击窗口上的关闭按钮时,它将关闭,但是无法将其恢复。 为了解决这个问题,我们应该“隐藏”窗口,而不是在用户尝试关闭窗口时将其关闭。 Xcode模板的最新版本针对单个窗口应用程序使用情节提要和窗口控制器,除其窗口控制器外,无法将窗口的委托连接到其他对象。 因此,这给了我们两个选择:1.子类化NSWindowController; 2.用代码将窗口的委托连接到目标对象,例如一个NSViewController对象。 解决方案1.子类化NSWindowController 创建一个新的NSWindowController子类,并在头文件中添加协议一致性(如果使用Swift,则不这样): 目标C: @interface VCWindowController:NSWindowController @结束 在实现文件中: #import“ VCWindowController.h” @interface VCWindowController() @结束 @implementation VCWindowController -(void)windowDidLoad { [super windowDidLoad]; //实现此方法以处理从其nib文件加载窗口控制器的窗口之后的所有初始化。 } -(BOOL)windowShouldClose:(id)sender { [NSApp hide:nil]; 返回否; } @结束 迅速: 进口可可 VCWindowController类:NSWindowController,NSWindowDelegate { 是否需要初始化?(编码器:NSCoder){ super.init(编码器:编码器) } func windowShouldClose(sender:AnyObject)-> Bool { NSApp.hide(无) 返回假 } } 创建类后,现在可以将代码连接到窗口。 一种。 将窗口控制器设置为自定义NSWindowController子类: b。 右键单击Window,将“代理”连接到Window Controller对象: 现在构建并运行您的应用程序,单击“关闭”按钮将仅隐藏您的应用程序,而不是关闭它。 […]

为XCode项目安装Cocoa Pods

在这篇文章中,我将展示如何为Xcode项目安装Cocoa Pods 。 Cocoa Pods是Swift和Objective-C Cocoa项目的依赖项经理 。 安装 在安装XCode时,您还将获得gem ( RubyGems , Ruby包管理器 )。 此命令允许您安装Xcode的Cocoa Pods,而无需任何额外配置。 执行以下命令 sudo gem install cocoapods 在获取依赖包列表之后,您可以使用可可豆荚调用命令pod 。 但是,每个命令都必须在 Xcode项目的 根文件夹中执行 : pod init :在Xcode项目文件夹中创建一个空的初始PodFile 。 pod install :安装PodFile定义的PodFile 使用Cocoa Pods命令行 照常创建Xcode应用程序。 然后,在安装Cocoa Pods之后,您可以创建执行pod init的初始PodFile 在应用程序的根文件夹中。 之后,您将获得一个PodFile像这样: #取消注释下一行以定义项目的全局平台 #platform:ios,’9.0′ 定位 “我的应用名称” #如果您不使用Swift并且不想使用动态框架,请注释下一行 use_frameworks ! #我的应用名称荚 结束 如果您想添加一些Pod,例如Google Maps iOS SDK组件,则可以将其添加到target部分: […]

NSView和CALayer

我最近在构建macOS应用时遇到了动画问题。 我无法正确显示转换后的图层。 事情变得很时髦。 因此,我决定花一些时间再次阅读文档。 它带给我以下几点: 查看编程指南 核心动画编程指南 他们有这样的关系: NSView位于AppKit Framework内部,它可以成为层支持的视图,并添加硬件支持以渲染图形。 重要学习 使用CALayer后,视觉效果将由硬件渲染。 也就是说,纯NSView由CPU处理 与UIView相比,NSView具有翻转的坐标系。 NSView中的点(0,0)指向左下角 AppKit和NSView无法提供简单的方法来制作内容动画 实际上,Core Animation在macOS和iOS上是相同的。 但是,大多数iOS用户会使用UIView进行动画处理 核心动画利用keyPath定义要进行动画处理的内容 CATransaction可用于显式设置多个属性的动画 动画完成后,动画属性仍将保持原始值,因此视觉效果将在动画结束时跳回 在动画代码之后将动画属性设置为最终值 在设置锚点和其他转换之前,将子视图添加到视图层次结构 CATransform本身是一个值,而不是动画。 进行设置,图层将转换为该特定值。 我已经完成了一个示例项目,以通过沿x轴进行3D变换来展示上述知识。 harryworld / RenderedImageView RenderedImageView –学习CALayer github.com

什么时候是采用Swift 3的正确时间?

自苹果推出Swift以来已经两年了。 在最初的12个月中,我很犹豫地推荐Swift作为一种实现语言。 实际上,我认为我的确切话是“不”。 在Swift大一的时候,这些工具不稳定,语言和库还很不成熟。 但是,在过去的12个月中,语言在不断发展壮大。 苹果公司开源了Swift,并通过Swift.org向更广泛的社区开放了该语言的发展。 这鼓励了社区通过Swift Evolution流程对Swift做出的巨大贡献,而即将发布的Swift 3也从这些努力中取得了成果。 Swift 3带来了该语言在其短生命周期中所看到的最重大的变化。 Swift 3和“伟大的重命名” Swift 3带来的最重大更改可能是“ The Great Renaming”。 去年这一年,Swift Evolution Process提出了许多建议,以澄清和标准化Swift标准库的命名方案,以及Swift如何导入Apple现有的框架(如Foundation,UIKit和Core Graphics)。 这产生了“ Swift API设计指南”。 这个新的命名标准意味着在使用这些框架时,Swift 3将与Swift 2完全不同。 随着向Swift 3的迁移,几乎所有现有的Swift代码都将需要迁移到新的命名标准并遵循这些准则。 Xcode 8包含一个迁移工具来帮助完成此过渡。 工具很棒,但是就像大多数工具一样,它可以节省您的工作,而不是从过程中消除所有想法。 我认为,所有Swift应用程序代码仍将需要由人工迁移来审核和审查。 此外,迁移工具无法帮助您将现有的应用程序代码转换为新的API准则。 它仅解决您的代码如何与Apple框架交互以及该API的更改方式。 Swift 3和ABI稳定性 Swift 3的目标之一是ABI稳定性。 这没有发生。 这意味着为了将项目升级到Swift 3,该项目的所有Swift依赖项也都需要更新到Swift3。不可能将Swift 3应用程序与Swift 2库链接。 在接下来的12个月中的某个时候,Sw​​ift 3很有可能达到ABI的稳定性,而在今年的WWDC上,克里斯·拉特纳(Chris Lattner)表示,在考虑日后对语言的更改时,保持源代码兼容性将是一个强大的约束。 因此,希望明年不再需要“ Great Renaming 2”。 何时切换到Swift 3? 团队现在应该开始为此进行计划。 […]

简化了iOS代码签名和设置流程

如果您曾经是iOS开发人员,那么肯定会在某些时候让您理解签署和部署应用程序这一相对复杂的过程。 捆绑标识符,置备配置文件,App ID或证书签名请求等有很多其他非常规术语,而所有这些之间的纠缠使整个过程变得如此复杂。 在本文中,我们将尝试理解并涵盖以下主题: 1.代码签名 2.供应流程 3.应用部署 A.与供应和代码签名有关的主要术语: 首先,让我们了解您在尝试对签名,部署和应用进行编码时将重复使用的基本术语。 1. Xcode和会员中心 Xcode是IDE,与XCode相关的任何帮助:http://help.apple.com/xcode/mac/9.0/ 会员中心是我们可以在其中创建配置文件,应用程序ID,证书等的门户。会员中心的一些功能直接与Xcode结合在一起。 例如,您可以在Xcode设置中查看和创建您的签名身份,或者下载和刷新预配配置文件。 在注册了Apple Developer Program之后,您将能够登录会员中心。 2.签署身份 通过对应用程序进行签名,iOS可以识别谁对您的应用程序进行了签名,并可以验证自从您对应用程序进行签名以来未对其进行修改。 签名身份由Apple为您创建的公私钥对组成。 将公钥视为仅锁定机制,因此您需要知道私钥才能再次展开,解锁或解码数据。 3.公钥和私钥,企业社会责任和钥匙串应用 公钥和私钥对来自哪里,您如何请求包含它们的证书? 通过“钥匙串访问”应用程序创建证书签名请求(CSR)时,所有这些都会发生。 如果这样做,“钥匙串应用程序”将创建一个私钥和一个certSigningRequest文件,然后将其上传到Apple。 Apple将验证该请求并为您颁发证书(如果会员中心由您的团队管理员管理,CSR的接受和证书的创建由团队管理员[证书颁发机构或CA]管理)。 4.证书 这是Apple授予的加密证书。 它的工作原理与SSL相似,在SSL中,您获得由权威机构签名的证书。 Apple签署了用于对应用程序的不同部分进行签名的私钥。 不同的证书创建不同类型的信任。 有些允许您签名并提交应用程序到App Store,而另一些允许您的应用程序的Web服务器通过APNS向用户发送推送通知。 证书将包含可以下载到系统的公共密钥。 下载后,您需要双击将其放入“钥匙串访问应用程序”。 加密功能使用它为您的应用程序生成唯一的签名,该签名基本上就是您的代码签名身份。 该证书也可以通过会员中心获得,但是它仅包含公共密钥,因此请确保该私有密钥的安全。 注意:钥匙串中还必须包含一个中间证书,以确保您的开发人员或发行证书是由另一个证书颁发机构颁发的。 第一次设置XCode时会自动安装它,因此基本上您不需要太在意它,因为它是手动配置的。 5.供应配置文件 作为安全措施,仅通过使用证书就无法在任何iOS设备上安装应用程序。 必须在应运行应用程序代码的每台设备上安装一个配置文件。 每个开发设置配置文件将包含一组iPhone开发证书,唯一设备标识符和一个应用程序ID。 应用程序ID是两部分的字符串,用于标识单个开发团队中的一个或多个应用程序。 简而言之,Provisioning配置文件说:“具有使用此证书的私钥签名的标识符的应用程序可以在这些设备上运行。” 由于配置文件与证书相关联,因此很明显,我们必须决定是否要创建证书 1.开发或发行档案。 2.开发配置文件限制为100个设备。 3.分发配置文件可以是Ad-Hoc或App Store分发配置文件。 6.标识符 也称为“应用程序标识符”或“捆绑包标识符”。 它们唯一地标识您的应用程序,并且通常具有反向域名,例如com.company.product 应用程序ID是两部分的字符串,用于标识单个开发团队中的一个或多个应用程序。 该字符串由Team […]

揭秘SKWarpGeometry

tl; dr :我构建了一个编辑器来使用本机SpriteKit扭曲图像 看起来像我所需要的,但是设置需要手动输入float2的数组-我实在太懒了,无法手动找出所有输入。 我需要一个小工具来调整输入,查看结果并导出。 听起来很简单… 要求 我希望能够加载图像,设置列和行,拉动控制点并将结果导出为Swift代码。 我打开了Xcode,并使用Game项目和SpriteKit&Swift创建了一个新的macOS项目。 我花了几个小时来整理所需的框架,使用NSSplitView和容器视图将视图控制器分离出来,第一个版本如下所示: 在这一点上,我可以加载磁盘映像,显示一个简单的检查器,并在时间轴上显示一个项目…。什么都没有用,因为它是伪造的,您无法选择图像上的黄色手柄,因此检查员的物品什么也没做。 但是我知道我必须证明移动控制点会扭曲精灵。 我在晚上和周末进行此操作,因此在短时间后,我可以拖动控制点并扭曲图像……它开始慢慢融合在一起。 我知道我希望能够单击控制手柄(黄色正方形)并四处移动,并查看精灵的变化。 考虑到这一点,我知道我必须拥有一个Inspector……就像在Xcode中一样,无论您选择什么,都可以拥有一个上下文相关的属性列表,您可以每周两次。 我还知道,通过阅读Apple文档,我可以按顺序应用任意数量的扭曲,因此我决定使用时间轴/图层系统。 同样,这应该是上下文相关的。 除此之外,我还知道整个场景可以具有列*行的任意组合,因此需要一个总体模型来存储它们,因此我填写了一个数据模型,如下所示: 文件模型 — WarpModel — — ControlPointModel DocumentModel将存储: *要使用的图片(实际上只是图片的URL) *控制点的列数和行数。 *经层 WarpModel将存储 * ControlPoints列表 ControlPointModel将存储 *位置,简单的X,Y坐标 我希望我的工具能够保存我决定变形的任何图像的结构,因此我需要实现Swift 4的新Codable接口。 它非常易于使用,并且可以轻松地将数据编码和解码为JSON。 “很容易看到一个简单的想法如何变成许多功能” 然后,我需要(那里不存在很多)来证明我可以从一个几何图形动画到下一个几何图形。 那意味着必须有多层。 每个图层都有自己的一组控制点…但是我想在它们之间设置动画。 图层应具有不同的起点/终点。 如果它们同时启动,您将获得混合结果。 导出代码是应用程序最重要的功能,我不想只看到变形的结果,我需要将其导出并在另一个项目中使用。 每当我对数据进行更改时,该应用程序都会重新生成Swift代码,您可以根据需要复制/粘贴该代码。 选单 再一次,我发现自己要添加要素,在某些位置添加图层,如果您想随时间推移稍微移动控制点,则可以复制图层。 上下移动控制点,旋转控制点。 撤销重做 我不打算构建的另一个功能是撤消/重做,但这确实使您可以将代码结构化为可重用的组件。 我很高兴我做到了。 网格切换 在开发应用程序时,我发现我想像在回放模式下那样打开和关闭网格,或者在擦拭时间轴时希望看到结果,而不是网格使子画面模糊。 我还想查看经线与原始源图像的偏离程度,因此我添加了一个洋葱皮类型的功能,可以在其中看到原始图像,但是在需要时将其关闭 容器视图 容器视图允许您将视图控制器引用嵌入到另一个视图中,这可以使您分离视图。 […]

在iOS上获取文字大小

我目前正在使用使用第三方聊天软件的iPhone应用程序。 向其中添加一些自定义消息类型需要在显示单元格之前计算收集单元格的高度。 我不记得所有的iOS API,但是在Google上进行的快速搜索只是显示了一个UIFont扩展名,该扩展名可以计算文本框(UILabel或TextView)的大小。 就像这样: 回到Google,寻找错误报告或可以告诉我为什么这么简单的东西不能与表情符号一起使用的东西。 我使用UILabel sizeToFit方法找到了一些要求相同的帖子,一个指向了我已经知道的方向。 好的,每次需要一个单元格高度时都创建一个UILabel并不完美,但是此集合视图会缓存高度,因此我可以忍受。 更改了我的方法以使用sizeToFit而不是boundingRectWithSize和… FAIL 使用sizeToFit返回的大小与boundingRectWithSize相同,我无法相信这两个方法都忽略了表情符号。 那是片刻停下来思考的时刻:“应该有一种方法可以做到这一点,但可能并不那么容易”。 这使我开始寻找在iOS中获取文字大小的简单方法。 我的第一次搜索与CoreText有关,并且得到的结果指出了正确的方向:CTFramesetter 这是我从未使用过的东西,但却是我唯一的选择,因此我去了官方API文档并再次更改了扩展方法以使用它。 结果? 有效!! 我不确定速度有多快,但已解决了我遇到的重大问题。 如果您发现相同的问题,希望您能找到这篇文章,然后可以将以下代码复制粘贴到您的应用中: 希望我能节省一些时间给下一个尝试根据宽度限制计算文本高度的人,如果有人知道更好的方法,请分享!

豆荚,迦太基和SPM:Swift的包装管理困境

到2019年,Swift已从Apple的少数几个开源项目之一发展成为一种功能强大的语言,成为Apple系统开发背后的强大力量,甚至还扩展到了Linux等其他操作系统。 现在处于4.2版中,期待已久的Swift 5发行版,Swift因其协议定位和为多个平台编写本机应用程序的能力而变得非常流行。 Swift 3是所有Swift用户和开发人员的标志性版本:它是代码破解版本,更改了大多数语法,删除了语言方面并添加了其他内容,并引入了其他主要工具和增强功能,例如Swift Package Manager和Swift Linux的核心库。 但是,随着Swift 3的到来,对开发人员来说,另一个艰难的决定。 Swift软件包管理器(Swift Package Manager)是Swift开发人员的第三个软件包管理器,但也是第一个正式软件包管理器,现已投入使用,使库和框架的选择和分发过程更加多样化。 Swift的包装管理困境 Google的词典将困境定义为“必须在两个或多个替代方案之间做出艰难选择的情况,尤其是同样令人讨厌的替代方案。”现在,我不会说所有可用的软件包管理器都是令人讨厌的,但我可以同意,它们都不是完美的。 与任何软件一样,程序包管理器都有其成功之处和不足之处,尽管每种缺点在开发中使用时都可能导致麻烦。 Swift的三个主要包管理器是Cocoapods,Carthage和Swift包管理器(SPM)。 Cocoapods是该小组中的老大,自从Objective-C是Apple的主要软件开发语言以来就一直存在。 Cocoapods最初于2011年9月17日发布,最初是为使用面向对象的C风格语言的库和框架提供服务的,为随之而来的软件包管理者铺平了道路。 当Swift成为主流时,Cocoapods慷慨地扩展到包括新语言的库和框架,新语言是其他程序包管理器将在以后建立的语言。 当2014年11月到来时,下一个软件包管理器发布了,这意味着Cocoapods不再是使用Xcode的那些的唯一发行商。 多种选择的能力都很强,这使得最初的Swift软件包管理器引起了争议。 尽管许多人认为它对Swift和Objective-C开发人员来说是革命性的,但其他人却因为它的明显缺点对其进行了轰炸。 Cocoapod最显着的功能之一就是它完全自动化了依赖程序,开发人员只需运行pod install ,Cocoapods便会获取并构建依赖项,将其插入项目中,将其链接到项目中,并生成一个包含两者的工作区。项目和豆荚。 事实证明,虽然该功能是主要的便利,但开发人员并不完全满意:尽管该过程确实节省了他们大量的时间和精力,但它也将对项目的控制权移交给了Cocoapods并让其处理文件和项目设置。 开发人员感到这是一种无声的痛苦,直到下一个程序包管理器发布时,这种痛苦才得以表达。 随着时间的流逝,开发人员对允许流行的第三方掌控为其项目构建程序包的满意度越来越低。 尽管较新的软件包管理器是用Swift编写的,但对于Swift而言,Cocoapods是用Ruby编写的,这意味着开发人员确实需要熟悉该语言才能操作软件包管理器。 许多人确实知道Ruby,而且学习曲线并不复杂,因此添加另一种语言的文件带来的不便并不麻烦。 但是,Swift的软件包管理器不是用自己的语言(例如Nuget,PyPi或NPM)编写的,而不得不使用另一种语言的事实给开发人员带来了痛苦。 Cocoapods是集中式的,这在软件包管理器中很常见(一个常见的指标是软件包注册表)。 程序包管理器中的集中化意味着存在一个中央代码注册表,可以在其中托管和查看程序包,并且客户端(通常是命令行界面)可以从中提取代码以生成程序包。 可以从cocoapods.org上浏览其网络上托管的所有Pod,这对于那些没有特定软件包或只想浏览可用软件包的开发人员来说非常有用。 但是,许多人似乎对新的分散化概念感到迷惑,这意味着Cocoapods不再是理想的包裹管理系统。 尽管Cocoapods有其缺点,并且最近一直受到嘲笑,但是它仍然是Swift的包管理器中最古老的,并且由于其自动化,对初学者非常友好。 CocoaPods.org iOS和Mac项目的依赖管理器 cocoapods.org 迦太基是第二位进入该小组的包装经理,从一开始它就与Cocoapods的主要区别显而易见。 它于2014年11月18日发布,在Swift 1.1正式发布后仅两个月就可用,并且支持Swift中的Objective-C。 迦太基在Cocoapods中发现了一个对开发人员来说很酸的话题:虽然Cocoapods是用Ruby编写的,但是Carthage完全用Swift编写了一个包管理器来迎合用户。 除了以Apple支持的语言以及您的项目被编写时,依赖管理的强大功能之外,Carthage还声称它利用Xcode的构建系统,同时为开发人员提供了集成其依赖的自由。 通过迦太基,开发人员可以控制他们项目的依赖关系,从而使他们能够在迦太基构建之后,根据自己的选择进行链接和管理。 第一次学习如何将Carthage集成到您的项目中(以及随后针对更复杂的需求)时,Carthage的README具有令人难以置信的描述性和实用性,但是对于经验较少的开发人员来说,开始使用它可能非常复杂。 但是,随着集成过程的延长,从长远来看,它将带来更多的简化和控制。 设置好迦太基并链接了依赖项后,只需要将一行添加到一个非常简单的文件(而不是将一行或多行添加到Ruby文件)和一个命令, carthage update ,就可以生成新的框架。可以导入原始文件的方式。 迦太基消除了在较大的.xcworkspace中处理多个.xcproject文件的麻烦,并消除了与核心项目一起添加的庞大文件结构,而仅在项目根目录中使用.framework文件夹对项目进行了补充,该文件夹清楚地说明了名称。框架。 迦太基提供了Swift,Objective-C或其他语言的其他软件包管理器所没有的某种程度的控制,那就是完全控制。 刚开始创建运行脚本并将框架链接到项目似乎很困难,但是一旦习惯后,该过程将变得异常顺利。 […]