Tag: swift

迅速。 以编程方式处理本地化字符串(没有情节提要)

很久以前,我曾经在应用程序中搜索处理本地化的方法,但是我发现的大多数都是示例,基于情节提要的解决方案。 但是我需要的是完全相反的东西,即没有使用情节提要。 但是幸运的是,最终我找到了解决方案,而且非常容易。 因此,让我们完成以下步骤: 在应用程序目录的Resources文件夹中创建一个名为Localizable的文件,扩展名为.string。 在这里,您以字典的形式存储所有带有本地化版本的字符串,因此您可以通过键轻松访问任何字符串的本地化版本。 例如,我只需要与现有字符串等效的俄语版本,因此我只创建了一个扩展名为.string的文件。 2.使用名为localize()-> String的方法扩展String结构。 3.当我们将所有字符串存储为字典时,将使用键搜索它们。 // 1:在这里,我们查找存储在设置控制器中设置的UserDefaults中的语言。 // 2:在这里,我们检查UserDefaults中存储的语言是否等于值1(在这种情况下,这表示俄语),我们进行可选绑定,因为通过键访问的字典始终返回可选值。 因此,如果存在这样的字符串,我们将其返回。 // 3:对于0情况,它返回的字符串本身没有任何本地化版本,因为0表示此应用中的默认哈萨克语。 // 4:默认情况下始终返回字符串本身。 // 5:最后一种情况是用我们给出的键找不到值的情况。 在这里,我们也返回自我。 综上所述,这是一个非常简单的解决方法,可以通过String来处理iOS中的本地化字符串。 感谢您的关注。 希望它有用。

使用Marathon with在Swift中使用脚本提高生产力

在iOS开发过程中,总会出现在整个项目中执行重复性任务的情况。 乍一看,您可能会发现其中的一些,后来又发现。 有可能: 管理所有项目资产,有时调整它们的大小以适合适当的尺寸,最后添加到Xcode项目中。 使用所有必需的文件(例如ViewControllers,Views,ViewModels等)创建新屏幕的文件夹结构。 在Fastlane和Quicktype之前,您需要手动执行以下任务: 在Testflight / Fabric上部署应用程序 根据API JSON响应创建模型 好消息是,iOS社区正在发展,并且有越来越多的工具可以自动执行日常开发流程,例如Sourcery或SwiftGen。 但是,如果它们都不满足您的需求怎么办? 您是否应该继续前进并继续手动重复进行所有操作? 还是应该使它们自动化? 好的,让我们写一些脚本,但是… 实际上,不需要使用Bash,Python,Ruby或其他脚本语言,因为Swift提供了编写脚本的功能。 与Marathon结合使用,在OSX上编写和安装脚本确实非常容易。 Marathon生成一个Xcode项目,并允许在脚本代码中使用依赖项。 让我们编写一个程序,该程序将生成具有所有所需类的自定义应用程序的屏幕文件夹结构。 在这种情况下,它将是“ 登录”屏幕文件夹。 每个文件都将包含样板代码以及已导入的所有必需库。 首先,让我们安装马拉松。 在撰写本文时,Homebrew还不支持最新版本的Marathon,因此我建议您通过Swift Package Manager安装它。 打开终端并输入: $ git clone https://github.com/JohnSundell/Marathon.git $ cd马拉松 $使 成功安装Marathon之后,第二步是创建FilesGenerator项目 $➜马拉松创建FilesGenerator $ Files在FilesGenerator.swift中创建脚本 $✏️打开FilesGenerator.xcodeproj / 它应该打开一个包含main.swift文件的Xcode项目 因为我们要对文件进行操作,所以最好添加名为Files的帮助程序依赖项。 让我们通过执行命令来做到这一点: $ marathon add https://github.com/JohnSundell/Files.git 关闭您的Xcode项目,然后输入以下内容再次将其打开: $ marathon edit FilesGenerator.swift 您应该看到添加了文件依赖关系的新的依赖关系目录。 现在,我们准备进行第三步编码。 […]

建立自己的框架库

框架是导入常用方法以及共享代码和与其他开发人员协作的非常有用的方法! 什么是框架? 框架是模块的一种类型:构建在一起并一起交付的已编译代码集合。 假设您在许多项目中经常使用几种方法。 您可以将这些方法从一张纸复制并粘贴到另一张纸,但是在项目文件夹中进行挖掘以查找代码行可能会非常麻烦。 相反,您可以将最常用的方法编译到单个.swift文件中,然后像导入其他任何框架(如UIKit或Foundation)一样将其导入。 Xcode带有各种内置扩展名,例如.count和.sorted,但是在本示例中,我们将使用可在Array类型上使用的.shuffle()方法。 它会使用交换功能“随机”地对数组中的值进行混洗,并且可以应用于[Int],[String]和任何类型的数组! 确保将您的扩展名声明为“公共扩展名”,以便在被调用时可以轻松访问它! 现在我们已经保存了我们喜欢的方法的.swift文件,我们可以开始构建我们的框架了。 建立框架 在Xcode中,您可以像其他任何项目一样构建框架,但是这次不用选择“单视图应用程序”,而是向下滚动并选择“ Cocoa Touch Framework”。 现在,通过将源文件 (刚创建的.swift文件)拖动到项目中或单击Xco​​de左下角的+,将其添加到框架的文件夹中。 导航器现在看起来应与以下类似: 大! 一旦完成,就可以关闭框架并创建一个新的Xcode项目(或打开任何现有项目)。 使用与上述完全相同的方法,通过找到框架的.xcodeproject文件并将其拖动或添加到Xcode项目中,将框架添加到Xcode项目中。 同样,请确保其正确嵌套! 现在,您的框架已成为项目的一部分,但它们尚未真正沟通。 要解决此问题,请打开框架的“产品”文件夹。 接下来,单击导航栏中的顶部项目(您的项目名称),然后在相应的页面上向下滚动到Embedded Binaries。 在此处,单击框架的.framework并将其从Products文件夹拖到Embedded Binaries中。 下一部分有点深奥,但是我发现它使导入运行更加顺畅。 单击同一屏幕的“构建设置”,然后向下滚动,直到找到“搜索路径”。 在“框架搜索路径”和“标题搜索路径”下,添加$(SRCROOT)并使其递归。 设置完之后,就该构建了! CMD + B 好,很好! 那么,我们现在该怎么办……行得通吗? 让我们找出答案! 转到您的ViewController(或您将要处理的任何文件)。 在顶部,尝试仅通过输入“ import”和您的框架名称(理想情况下应自动显示)来导入框架。 还有……瞧! 现在,您在框架中拥有的任何扩展类型都应适用于项目中的该值。 但是,哦,不……您忘记添加方法了吗? 不要害怕! 您可以随时关闭项目并更新框架,新框架将在您的项目中显示为最新! 现在就这些了,我希望这个简单而简短的教程将有助于使您的所有编码生活变得更加懒惰,更轻松,更高效。

自动布局:朋友还是敌人? / 技巧和窍门

这是“自动版面设计”两部分系列中的第二部分 在开始本周的文章之前,我想提供一些信息,说明为什么我不能在上一个星期日上传文章。 有了所有的Iris公告(我加入Iris),我没有时间适当地审查我的草案并发布。 另外,我不喜欢发表自己不喜欢自己读的东西。 我已经说过,我真的很喜欢自动布局。 我从这个分为两部分的系列文章开始,讨论了我认为该技术具有的优势。 你们中的许多人已经知道,在这一部分中,我将与您分享一些我最喜欢的技巧和窍门,我认为这些技巧将促进您的工作流程。 堆栈视图 如果您还不了解,请使用iOS 9引入的堆栈视图,这是我自动布局时最喜欢使用的视图之一。 让我解释。 例如,您有一张照片和一个标签,并且想要对齐它们。 一个很好的解决方案是使用堆栈视图。 之后,您将不得不考虑将约束添加到VC(堆栈视图)中的单个对象,而不是其中两个。 (图片和标签) 使用字体或颜色属性左侧的+按钮 使您的应用程序具有适应性并为您的用户创造出色的体验比以往任何时候都容易。 在字体方面,iPad的分辨率需要比iPhone的分辨率大。 您可以按添加按钮轻松转到字体选择器,并为特定的大小类创建第二个字体属性。 Yay🎉Ps为了获得更好的适应性,请使用系统字体。 它是SF字体,当您想为应用程序添加可访问性支持时,它非常有用。 专注于一组特定的设备 当您开始构想并且想要在Xcode中“导入”设计并使应用程序具有自适应性时,我强烈建议您首先需要关注一组特定的设备(例如iPhone),然后是iPad。 自动布局可以节省大量时间。 您将更有条理,更有效率。 避免保证金选项 我也强烈建议您避免使用任何包含保证金的选项。 它确实会弄乱您的布局和约束。 同样,在那之后,您将搜索约束/布局出了什么问题,而我上面提到的原因将是让您整夜不知所措的原因之一。 我对自动版式及其多年来如何帮助我轻松创建自己的版式感到不满意。 在上面,您阅读了我最喜欢的提示和技巧。 不要对自动布局感到“恐惧”并接受它。

自调整TableView单元格

最近,一些初级的iOS开发人员向我询问了可自动调整大小的tableview单元(根据其内容增长的单元),并意识到从理论上解释它的工作原理是一个不错的起点,但是有一个示例对其进行备份甚至更好。 因此,今天我们将在上方创建聊天单元! 自定义大小的单元格根据其子视图的大小要求确定其大小。 正确设置高度的技巧是防止高度模糊的布局约束。 那是什么意思呢? 例如,一个标签被限制在单元格内容视图的顶部和顶部锚点上。 随着文本长度的增加,标签会垂直增加吗? 还是水平? 或两者? 在什么条件下? 横向增长是无限的吗? 这就是我含糊不清的意思。 答案当然是,鉴于当前的限制,标签将无限制地水平增长。 这是不好的。 我们的单元应具有最大宽度和可变高度。 那么该怎么办? 首先,让我们谈谈一般策略。 可以将单元格的contentView看作是矩形橡皮筋。 只要子视图共同顶着顶部和底部,并一直向上和向下相互抵触,从而形成类似堆栈的结构,则内容视图(如橡皮筋)将拉伸以容纳其子视图-使用集体固有尺寸其子视图的大小。 好的讨论,让我们进入代码,看看我们可以学到什么! 从总体上讲,这是我们的目标结构。 橙色勾勒出内容视图,蓝色圆圈勾勒出图像视图,红色代表标签,绿色代表标签的超级视图,这就是我们将要应用的圆角半径以及赋予标签的原因文字气泡边缘的一些填充。 ChatCell.swift 重要的是要注意messageLabel的numberOfLines属性必须设置为0。 仔细检查第50–62行的约束,您会发现以下几点: 所有子视图都限制在其各自的父视图的顶部和底部。 图像视图具有固定的大小,但也具有lessThanOrEqualTo底部约束。 messageBackground没有明确的高度,但其尾锚具有最大值。 它还具有lessThanOrEqualTo底部约束。 messageLabel在它和messageBackground之间有一个边距,但是它限制在messageBackground的所有边缘。 首先确保子视图与contentView的顶部和底部相对。 第二个方法确保如果messageBackground小于imageView的固定大小,则imageView将直接推向contentView的底部,确定其高度。 如果messageBackground大于imageView? lessThanOrEqual to bottom约束将确保imageView不会被拉长,因为它可以进一步远离底部。 第三,从lessThanOrEqualTo底部约束开始,将保证与上述图像视图的底部约束相同的行为。 真正的钱是,第三个提供了消息背景的最大宽度,这意味着在达到最大值之后,messageLabel将被迫向下增长,从而导致高度增加🙌🏽 与第四个项目符号结合使用,因为标签卡在messageBackground上,所以随着标签的增长,背景将被迫增长。 随着背景的增长,contentView也将随之增长! 🎉 您需要做的最后一件事是设置表视图的rowHeight和estimatedRowHeight如下所示: tableview.rowHeight = UITableViewAutomaticDimension tableview.estimatedRowHeight = 50 只是为了让您不知道为什么,这是来自Apple的直接解释: 要启用自动调整大小的表格视图单元格,必须将表格视图的rowHeight属性设置为UITableViewAutomaticDimension 。 您还必须将一个值分配给estimatedRowHeight属性。 一旦设置了这两个属性,系统就会使用“自动布局”来计算行的实际高度。 就像这样,我们有自动调整大小的单元! 👏🏽 […]

如何创建像iOS 11 App Store这样的侧面偷看的单元格

集合视图的滚动和分页一直是我的一个谜。 直到最近,我们才有一个项目的需求,在该项目中,有一个集合视图显示了上一个和下一个项目的一部分。 因此,现在该深入研究实现此功能了。 我最终决定实现自己的逻辑并从中创建一个pod,以便可以轻松地将其集成到项目中。 该功能在此处可用: MaherKSantina / MSPeekCollectionViewDelegateImplementation MSPeekCollectionViewDelegateImplementation –一种自定义的分页行为,可在页面中窥视上一个和下一个项目 github.com 自述文件包含使之正常运行所需的所有必要信息。 为了方便起见,下面是一个示例: 如果您有兴趣了解MSPeekCollectionViewDelegateImplementation的内部工作原理,请继续下一节。 本节将介绍偷看委托实现的主要功能。 (此处未显示所有代码,但Github存储库中包含所有代码) 我们将不依赖集合视图中已经存在的分页行为,而是将实现自己的逻辑。 因此,“ Paging Enabled复选框将被取消选中。 布局: 这是一个显示视图的不同组件的图: 您可以使用委托函数为像元间距设置任何值: 我们可以使用委托函数来做到这一点: 在索引路径处插入段 由于单元格将占据剩余空间,因此我们可以设置单元格的项目大小,如下面的委托函数所示: 索引路径中项目的大小 由于有两个从侧面窥视的单元格,因此从左右两个单元格之间有两个空格,可以使用以下公式计算itemWidth: 让itemWidth = collectionView.frame.size.width-2 *(cellSpacing + cellPeekWidth) 如果集合视图的宽度小于peek +间距,则max函数仅用于防止出现负值。 为了安全起见,我们还将最小项目间距设置为0: 最小项目间距 逻辑: 我们将引入一个名为scrollThreshold的新参数。 这将确定需要多少滚动才能捕捉到相邻的单元格。 当用户开始使用以下命令拖动时,我们将通过保存滚动偏移量来计算滚动距离: 滚动视图将开始拖动 这是主要部分。 我们可以使用委托函数scrollViewWillEndDragging来实现逻辑。 滚动视图将结束拖动 让我们将其分为几个步骤: 我们从targetContentOffset指针获取滚动视图将停止拖动的目的地。 指针指向滚动视图将停止的位置。 更改此值将更改滚动视图停止的位置,并且它将自动为其设置动画,而无需进行任何额外的工作。 计算滚动的总距离。 检查滚动的幅度是否大于scrollThreshold并创建一个系数,该系数具有3个值(-1、0、1)之一。 这将被添加到当前索引中。 通过将偏移量除以项目宽度来获取当前索引 将在步骤3中检索到的系数添加到当前索引。 […]

UIKit:圆形视图

让我们以简单而又令人沮丧的入门技巧开始这一系列的“快速药丸”,以使视图的角变圆。 这是代码: myView.layer.cornerRadius = 20 myView.layer.masksToBounds = true 如果要使用圆形视图,请在界面构建器中创建一个正方形视图,并将其半径设置为其宽度(或高度🔲)的一半: myView.layer.cornerRadius = myButton.frame.width * 0.5 myView.layer.masksToBounds = true 最后但并非最不重要的一点是,从iOS 11.0+起,您只能舍入某些特定的角: myView.layer.cornerRadius = 20 myView.layer.maskedCorners = [ .layerMaxXMaxYCorner, .layerMinXMaxYCorner ] UIKit中的每个视图都有一个类型为CALayer的属性layer ,该属性layer实际上管理渲染,并且具有您可以设置的自己的视觉属性,例如背景色,边框和阴影。 我通常在didSet属性观察器中设置此属性,以避免通过可视化自定义污染viewDidLoad方法: @IBOutlet弱var myButton:UIButton! { didSet { myButton.layer.cornerRadius = 20 myButton.layer.masksToBounds = true } } 下次我将向您展示如何在视图中添加阴影,现在桌上放着炸鱿鱼等着我waiting Github上的代码 Donald90 /快速药丸 SwiftPills – XCode项目,其中包含有关Medium的Swift Pills系列中介绍的每个概念的示例。 github.com 参考文献 卡拉耶 […]

使用Swift枚举组织XCUIElement

使用XCUITest框架自动化iOS应用程序可以确保从用户的角度来看,该应用程序可以按预期运行。 自Apple在WWDC 2015中推出UI测试支持以来,此框架在iOS开发人员中广受欢迎,因为他们现在可以在Swift和XCTest框架中编写与单元测​​试相同的UI测试。 在这篇简短的文章中,我们将看到如何更好地使用Swift枚举在屏幕上组织XCUIElements(即定位器)。 这是我一个聪明的同事在工作中分享的一个简短技巧。 在Selenium或Appium世界中,您可能听说过一些用于抽象或存储UI元素的模式,例如页面对象或屏幕播放。 我们可以将UI元素存储在单独的类或Struct中,然后可以在测试或步骤定义等中访问这些元素。在Swift中,我们可以利用Swift枚举来存储我们的UI元素(也称为XCUIElements)。 Swift枚举比类和结构好得多,因为我们可以根据需要向枚举添加函数。 使用枚举的另一个好处是,我们可以在整个UI目标上访问枚举,而无需创建对象或引用为静态值。 假设我们的iOS应用程序有一个主屏幕,其中包含3个按钮,2个静态文本。 我们可以很容易地用这6种情况编写一个枚举。 导入XCTest 枚举HomeScreen:字符串{ 案例guestButton 案例寄存器按钮 案例loginButton 案例welcomeText 案例介绍 var元素:XCUIElement { 切换自我{ case .guestButton: 返回XCUIApplication()。buttons [“ Hello”] 案例.registerButton: 返回XCUIApplication()。buttons [“注册”] 案例.loginButton: 返回XCUIApplication()。buttons [“登录”] 案例.welcomeText: 返回XCUIApplication()。staticTexts [“ Welcome”] 案例.introText: 返回XCUIApplication()。staticTexts [“ app简介”] } } } 现在,我们已经使用可以在UI测试目标中任何位置使用的Swift枚举定义了主屏幕中的所有元素。 这是我以前采用的一种方法,在我之前编写的BDD工具XCFit中也对此进行了说明。 这种方法没有错,因为我们可以根据需要独立访问所有这些元素。 但是,有一种更好的方法可以使用Swift枚举,这样我们可以节省很多代码并仍然达到相同的结果。 在前面提到的方法中,我们已经分别定义了所有元素,我们可以通过以下方式重构上面的枚举 按类型对XCUIElement进行分组,例如按钮,静态文本 将值分配给枚举案例,通常是元素的可访问性标识符 然后,我们可以在XCUIElements中使用案例的原始值。 因此,我们可以重构上面的枚举,如下所示。 导入XCTest 枚举HomeScreen:字符串{ case […]

核心动画宝石:在Swift中使用复制器层

要阅读所有代码示例的语法突出显示的帖子,请 转到Swift By Sundell ,您还可以在其中找到我的所有其他每周帖子和新播客👍 如果您曾经将像素推到Apple设备的屏幕上,则可以直接或间接使用Core Animation。 像苹果公司大多数核心框架系列一样,它是那些必不可少的技术之一,这些技术支撑着我们每天使用的众多工具-无论我们针对的是哪个平台。 尽管有大量关于核心动画的最常用API的出色教程和资源,例如使用CALayer为UIView执行更底层的渲染,或使用动画API(例如CAKeyframeAnimation ,但也有一些非常有用的尚未广为人知的功能。 在这个新的(非连续的)系列文章“核心动画宝石”中,我们将仔细研究其中的一些功能和API,以及如何使用它们来很好地解决与动画和渲染相关的问题。办法。 这周,让我们从第一个💎CAReplicatorLayer CAReplicatorLayer 。 专业化 Core Animation的图层类的体系结构非常围绕专业化的思想。 您拥有根类CALayer ,该类基本上是可以在其上绘制任何内容的通用画布,然后您可以拥有一系列专门用于某种渲染的子类。 CAReplicatorLayer专门以一种有效的,硬件加速的方式绘制原始层的多个副本(因此它是“复制者” )。 当绘制平铺背景,图案或其他应重复多次的内容时,此功能非常有用。 我什至用它来实现我即将发布的开源Swift游戏引擎的纹理平铺功能。 您的UIColor可以做到吗? 使用重复图像实现背景的一种非常常见的方法是使用UIColor ,它具有一个采用patternImage的初始化patternImage 。 它使您可以将重复的图像序列视为一种颜色,并将其用作背景,如下所示: view.backgroundColor = UIColor(patternImage: image) 在某些情况下,尽管绘制重复图像的方式可能正是您所需要的,但在其他情况下,您可能需要做一些更复杂的事情-这就是CAReplicatorLayer用武之地。 假设我们要绘制一个由重复图像组成的图案,但是我们也想用蓝色阴影对其进行着色,从而使该图案从图像的原始颜色形成渐变,直到完全着色为止,如下所示: 使用复制器层,无需任何自定义Core Graphics绘图代码即可轻松完成此操作。 让我们深入研究一下实现的外观。 设置东西 我们将从将复制器层设置为UIView层的子层开始,以便在屏幕上进行渲染(本文中的示例代码将针对iOS / tvOS,但其工作方式几乎完全相同苹果系统): let replicatorLayer = CAReplicatorLayer() replicatorLayer.frame.size = view.frame.size replicatorLayer.masksToBounds = true view.layer.addSublayer(replicatorLayer) 我们 masksToBounds 上面 […]

使用嵌入式框架将iOS应用程序划分为适当的层

由于我们正在开发的iOS应用程序的来源不断增加,因此我们将其重构为嵌入式框架(Cocoa Touch Framework)。 使用嵌入式Framewok的三个目的 澄清层划分 更快的构建时间 组织依赖性 之前 在拆分之前,应用程序有一个目标,我们通过在该文件夹下创建组来拆分源文件。 后 拆分后,我添加了以下四个框架,并将源分发到每个框架。 应用…iOS应用 API…与API交互的费用。 这取决于型号。 通用…完全像Foundation Extension或logger一样使用的通用功能。 模型…CoreData实体以及数据模型的类和结构。 存储…将数据保存到CoreData,Keychain,iCloud。 取决于型号和API。 考虑每个框架的依赖性 通过分解成框架,框架之间的依赖关系变得很清楚,因此我们必须考虑应将哪些源和类放入框架中。 由于反复试验的结果,我将以上四个框架分为几个框架,并组织了依赖关系。 添加访问修饰符 当所有源都在一个目标中时,它们都设置为默认的内部访问修饰符,但是如果划分为框架,则必须公开引用其他目标。 因此,我们还组织了访问修饰符。 在提到该框架时,我遇到一个错误,说没有类,有一段时间我不知道原因,但是访问修饰符是原因。 为每个框架添加标志 我们在自己的开发环境中使用调试标志和标志来执行运行时行为并为测试环境进行构建,但是我们还需要为每个框架添加它们。 选择框架的目标,然后从“其他构建设置的Swift标记”中添加它。 更改CoreData的初始化处理 对于围绕CoreData的初始化处理,我们使用NSPersistentContainer,但是将模型定义文件.xcdatamodeld放入了Model框架。 因此,在初始化NSPersistentContainer时,需要在Model中显式指定定义文件。 让modelURL = Bundle(for:Model.self中的类)。url(forResource:“资源名称”,withExtension:“ momd”)! 让妈妈= NSManagedObjectModel(contentsOf:modelURL)! 让容器= NSPersistentContainer(名称:“容器的名称”,managedObjectModel:妈妈) 在这部分中,您需要格外小心,在该部分中,使用Bundle.main读取资源。 日本语はこちら