Tag: swift

使用Swift在iOS中构建通用框架

我已经搜索了很多可靠的资源,这将有助于我在iOS上构建自定义通用框架。 我尝试实现多种技术,但它们并没有帮助我完成任务。 寻求和阅读很多东西有助于我了解更多有关它的知识,最终我建立了一个通用框架。 我想分享我如何轻松构建此框架, 创建可可触摸框架: 打开Xcode, 文件→新建→项目 。 在iOS下,选择Framework&Library,然后选择Cocoa Touch Framework,然后单击“下一步”。 输入您的框架名称,然后单击“下一步” 。 然后选择您的项目位置并创建项目。 选择您的项目,选择目标→项目名称→选择构建设置选项卡。 在构建框架之前,始终将“启用位码”设置为“是” 。 在项目中构建所需的功能。 如果需要,您可以维护多个情节提要。 Framework项目看起来像一个普通的SPA项目,唯一的区别是您只能编译/构建Framework,而实际上不能在同一项目中运行它们。 如果项目仅在“ Simulator”中构建,则它将生成使框架专门在模拟器而非设备上运行的体系结构。 或者,如果项目是在“设备”中构建的,则它将生成使框架仅在设备上运行的体系结构。 因此,在“ Simulator”和“ Device”上都构建项目。 该框架将在“ 产品”文件夹中生成。 该框架将在项目的产品目录中生成,该产品目录具有两个单独的独特框架文件夹,这些文件夹将分别在Simulator和Device上运行。 设备框架:它包含仅为物理设备构建的体系结构。 模拟器框架:它包含仅为模拟器构建的体系结构。 从开发人员的角度来看,开发人员希望获得一个同时在模拟器和Device上运行的通用框架 。 大多数“流行”框架都是作为通用框架构建的,例如Mixpanel,Fabric等, 我写了一个“运行脚本”来生成通用框架。 选择项目目标→编辑模式→归档→后操作→按“ +”→“新建运行脚本操作” 。 UNIVERSAL_OUTPUTFOLDER = $ {BUILD_DIR} / $ {CONFIGURATION}-通用 #确保输出目录存在 mkdir -p“ $ {UNIVERSAL_OUTPUTFOLDER}” #接下来,计算出我们是否在SIM卡或DEVICE中 xcodebuild -target“ $ {PROJECT_NAME}”-配置$ […]

Swift中的归因字符串:正确的方法

我们如何使可可少一些冗长,类型多一些安全。 当我在2001年晚些时候开始使用Cocoa时,我是从Java方面的经验和少量的纯C语言中学到的。Cocoa简直太了不起了(请查阅Ars Technica的这篇很酷的老文章),以及与旧Mac的区别。工具箱很大。 一个崭新的世界即将来临,我为所有机会提供了一个如此完整的,功能齐全的框架,这让我感到非常兴奋。 自从这些天以来,已经过去了很多年,古老的NeXT遗产是从iOS和UIKit继承而来的,我们也经历了移动革命,尤其是得益于完整的解决方案,该解决方案确实为我们所谓的应用经济创造了肥沃的环境( ,当然是在macOS上启动的。 使用Swift,就像时光倒流,再次体验相同的体验。 即使有这个新机会,UIKit(以及程度较小的AppKit)也正在经历向新生活的平稳过渡(虽然我的梦想是关于新的重写框架,但我可以理解选择平滑过渡的原因)。 Swift标准库中的基金会)。 因此,尽管我们仍在与这种过渡作斗争,但无论如何我们都可以使我们的生活更轻松。 NSAttributedString是我在后Swift时代开始讨厌的事情之一; 创建,组合样式并将其应用到字符串,然后将其渲染并不是一件困难的事情,但是它很无聊,冗长且令人讨厌。 就像不久前通过代码使用Auto Layout一样; 我们应该得到更好的体验,特别是现在我们正在使用Swift:我们可以使其变得类型安全,易于使用和简洁。 因此,从这种经验开始,我创建了一个名为SwiftRichString的小型库(原始名称,您认为不是吗?)。 类型安全 我要解决的第一个问题是关于类型安全的问题。 Swift实现类型安全 ,这基本上意味着您不能对变量的类型术语不恰当地使用它。 让开发环境强制执行类型安全是处理这些问题的最安全方法。 NSAttributedStrings使用NSDictionary设置文本属性; 属性标识符(作为字符串)及其值一起传递。 像那样: 为了使其更安全,我引入了样式的概念。 您可以使用名称创建样式(我们将在后面讨论),并使用传统的创建模式分配属性: 甚至font属性也是类型安全的; 您可以通过指定iOS提供的一种字体,以类型安全的方式创建UIFont对象。 FontAttribute也可以扩展,您可以添加自己的字体名称(或者,如果您很懒,可以通过指定文字以旧的方式实例化字体)。 通过查看库,您会发现其他一些特殊的结构,例如StrikeAttribute,ShadowAttribute或UnderlineAttribute。 所有这些都用于使事情变得更清洁,更快捷地使用(请查看文档以获取完整列表)。 样式的理想方案是创建将在下一个应用程序的代码中使用的一组样式。 只有一种特殊的样式称为.default。 无论将默认样式传递给函数的styles参数的顺序如何,默认样式都将首先应用。 这样可以确保您的字符串具有基本的通用样式,并可以在其上轻松添加一个或多个属性。 如果您不需要在代码中使用带标签的字符串,则可以创建Style对象而无需给它们命名。 只需在set()函数中使用它即可。 无痛属性字符串的创建和管理 创建NSAttributedString,将它们结合起来并应用样式既乏味又冗长; 大量无聊的代码使完成一项相当容易的任务。 让我向您展示一个非常简单的示例。 文章继续对我不利。 点击此处以继续阅读!

Swift中最常见的内存泄漏陷阱

如果您有内存循环,它将在调试器中向您显示警告: 如果确实有一个(或通常是一堆),则表示您有一个泄漏的物体。 您如何预防呢? 就像在关闭的第一行中添加[unowned self]一样简单! 而已! 它将阻止泄漏。 之所以会发生内存泄漏,是因为Swift中的闭包必须捕获作用域(即{}之间的所有东西)以及您引用的任何self. 它必须保留指向该对象的强大指针,并且即使整个viewController可能已被释放,也永远不会释放它。 [unowned self]是您在Swift闭包中的朋友! 更新:正如中型读者所指出的那样,也可以使用[weak self]代替[unowned self] ,这也将阻止泄漏 。 但是,Tudor Andrei Marinescu指出了一些重要的考虑因素: unowned和weak之间的区别在于, weak被声明为可选, unowned则不是。 通过声明它是weak您可以处理某些情况下它在闭包内部可能为零的情况。 如果您尝试访问一个恰好为nil的unowned变量,它将使整个程序崩溃。 因此,只有当您肯定变量在闭包周围时将始终存在时,才使用unowned

iOS 9.0、9.1、9.2上发生奇怪的崩溃

在具有Xcode 8和Swift 3的设备上调试时,显示具有Adobe RGB(1998)色彩空间的图像对我来说是可行的,但在iOS 9上没有发布。更改色彩空间使其可以工作。 —安德鲁(Andrew)2016年11月16日在16:59 让我们从发生在我身上的事情开始。 有一天,我收到用户的一封电子邮件,她说应用程序不断崩溃。 多亏了Fabric,我知道她在使用iPhone 6 plus和iOS 9.2。 从崩溃日志中,我知道加载子视图后应用程序崩溃的唯一线索,但是我无法在调试和发布模式下从自己的角度重现它。 环顾四周后,我可以仅通过存档和导出特定设备(iOS 9.0、9.1、9.2)进行复制。 看来这使我的生活更轻松,但这只是故事的开始。 导出ipa文件所需的时间太长,因此一旦尝试执行某些操作,则需要五到十分钟的时间来检查结果。 不幸的是,崩溃日志使我误入歧途。 它显示了相同崩溃点的不一致轨迹(您可以在本文的和处找到一些示例),并且它随机发生在不同位置。 我以为是内存泄漏问题,或者是自定义字体,自定义UI或情节提要等问题。 经过三天的尝试和失败,我找到了一个帖子。 这与我的情况并不完全相似。 就我而言,使用电缆进行调试时不会在模拟器或设备中发生,没有与“ ERROR ITMS-90682:Invalid Bundle”有关的线索。 Xcode 8在iOS 9.2及更低版本上崩溃 当我使用Xcode 8 GM Seed构建我的应用程序并在设备或模拟器下的iOS 9.2上运行它时,我感到很奇怪…… stackoverflow.com 但是,我决定像没有希望的猴子那样尝试脚本,但是很惊讶它正常工作。 #!/bin/bash DIRECTORY=$1 echo “——————————” echo “Passed Resources with xcassets folder argument is ” echo “——————————” echo “Processing asset:” find […]

IGListKit

今天,我们将探索IGListKit,这是一个数据驱动的UICollectionView框架,用于构建快速灵活的列表。 IGListKit是Instagram的开源项目。 该库背后的原因是,有时UICollectionView可能很难使用。 该库是Instagram Feed重构中出现的一种模式。 你可以在这里读更多关于它的内容。 IGListKit教程是一个很棒(有趣)的教程:如果您想学习如何使用该库,可以使用更好的UICollectionViews。 在Ryan Nystrom撰写的本教程中,您将深入研究最初仅使用UICollectionView开发的应用程序,然后使用IGListKit在较短的时间内(或上市)添加新功能。 您可以在此处检查最终项目。 该应用程序可为宇航员探索火星提供支持: 该库具有主要组件: IGListAdapter和IGListAdapterDataSource IGListSectionController实现IGListSectionType IGListCollectionView,集合视图 实现IGListUpdatingDelegate的IGListAdapterUpdater 要使用它,我们要拥有符合IGListDiffable的数据,并为我们拥有的不同类型的数据创建不同的节控制器。 然后在我们的视图控制器中,创建一个适配器,连接一个收集视图和一个数据源。 我们还创建了一个仅带有Label单元和一些硬编码数据的简单示例,您可以在此处找到。

使用EasyPeasy II掌握自动版面设计:基础知识

在本教程中,我们将介绍自动布局的基础知识。 如何放置UIView ,更新约束等,从根本上覆盖了NSLayoutConstraint的整个生命周期。 应用第一个约束 下面的屏幕快照在UIViewController视图中显示了一个蓝色的UIButton 。 没什么真正复杂的,宽50px高50px且视图与其视图的垂直和水平中心对齐。 为此,我们需要对视图应用四个EasyPeasy属性,每个属性分别对应前面提到的尺寸和位置分量(宽度,高度,centerX和centerY)之一。 为此,我们只需要应用我们感兴趣的新position属性:

带有Sourcery的元编程Swift

我们都讨厌复制和粘贴无聊的重复样板代码。 它发生在每个项目中,尤其是iOS。 它出现在我们代码库的许多地方,这间接违反了DRY原理。 我们都知道这是一个坏兆头。 这个问题通常不会引起足够的重视。 这涉及到脱离我们的舒适区,因为生成代码可能很困难。 幸运的是,我们有一个解决方案可以在Swift项目中开始自动执行样板代码。 我在办公室为我们的项目寻找解决方案时偶然发现了它。 我花了很长时间才使事情顺利进行,所以我决定从一个简单的例子开始。 让我们看一下这个例子: 现在,我们想在代码的不同地方比较我们的Car结构。 因此,我们对其进行了扩展以符合Equatable协议 有些人可能会说: 好吧,这是一种方法……4行代码和一些复制粘贴。 确实 还不错 。 考虑一下: 如果您在比较时错过了一个变量,那么Swift编译器将不会失败。 每次添加新属性时,都必须记住要手动重新访问此方法。 您可能具有跨多个文件(可哈希,描述,测试,枚举用例等)的多个样板功能。 处理这些案件将成为麻烦,重复和最危险的事情。 这是所有偷偷摸摸的运行时错误都可以轻松出现的地方。

iOS 10的应用程序组和iMessage扩展– Tack Mobile –中

Messages应用程序的可能性几乎是无穷无尽的,我很高兴看到iOS 10的发布在接下来的几个月中提出了其他独立或捆绑的创造性应用程序。对于我一直在从事的项目在过去的6-7个月中,我们希望通过Messages扩展程序使事情变得简单。 没有新功能,只有现有应用程序的简单功能扩展到了Messages,可以与当前没有该应用程序的人共享。 对于没有订阅功能的付费应用程序,新用户的招聘对于赚钱至关重要,这是创建Messages扩展的主要目标。 本质上,我们希望为用户提供一种更轻松的共享方式,从而通过消息向非用户推广。 第一步是创建一种在现有包含应用程序和Messages应用程序之间共享数据的方法。 本文底部已链接了有关创建App组以通过NSUserDefaults和Core Data共享数据的出色教程,我在创建Messages应用程序时引用了这些教程。 这篇文章是关于使用应用程序组通过NSFileManager共享iMessage扩展的数据。 我们已经在使用NSFileManager将要共享的数据写入磁盘。 本质上,我们遵循将数据托管在服务器上的通用模式,该服务器可根据需要提取并在本地写入/删除/读取。 由于我们已经使用NSFileManager写入文档目录,因此我使用NSFileManager与我们的消息应用程序共享数据。 就我的目的而言,Core Data可能会过大。 第一步是创建iMessage扩展。 从现有容器应用程序中,选择文件->新建->目标。 这将弹出此窗口: 选择“ iMessage扩展”,然后选择一个名称。 您可以稍后更改显示名称,并且显示名称可以与您的容器应用程序相同,这是我们选择执行的操作,因为扩展名旨在驱动用户购买容器应用程序。 要开始共享数据,您需要在“目标”功能中打开应用程序组。 这应将com.apple.security.application-groups添加到YourProject.entitlements文件,并在project.pbxproj文件中启用com.apple.ApplicationGroups.iOS。 需要明确的是,您并没有更改这些文件,当您在“目标”->“功能”中打开“应用程序组”时,它应该只显示在源代码控件中。 在新启用的“应用程序组”部分中,单击加号图标,Xcode将弹出一个视图,显示“添加新容器”。 这必须是唯一的,因此我遵循推荐的group.com.YourCompanyName.YourProjectName.container命名约定。 除不创建新容器外,还请按照消息目标中的这些相同步骤进行操作,只需选择刚刚创建的容器即可。 它是两个应用程序之间的共享容器。 确保两个目标都选中了您创建的容器,并且选中了“步骤:”下面的三个标记。 现在,您已经在两个目标中都启用了应用组,就可以开始编码了。 我做的第一件事是创建用于访问共享容器的辅助方法,因为它是我用于创建共享目录,写入数据和删除数据的路径。 您将要使用您在“项目设置”中“应用程序组”下创建的确切字符串。 我将其设置为常量,并使用NSFileManager方法containerURLForSecurityApplicationGroupIdentifier:创建了一个返回容器路径的方法,并传入了App Group常量。 在消息扩展之前,我们使用NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)将数据写入NSDocumentDirectory; 然后选择返回的第一个路径。 我更新了所有我们使用共享应用程序组容器的地方。 基本上,在使用此标准NSDocumentDirectory的任何地方,都需要对其进行更新以使用容器路径。 主要是在这里NSFileManager写入数据,获取数据和删除数据。 我们还有一个可用的磁盘空间检查,在这里我们检查attributeOfFileSystemForPath:并检查NSFileSystemFreeSize对象以查看剩余的磁盘空间,并且我还更新了此路径以检查容器路径而不是NSDocumentDirectory路径。 仔细检查文件管理器的工作并确保全面更新非常重要,因为您可以想象如果更新以将数据写入新容器但仍从NSDocumentDirectory等删除数据时可能会遇到的错误。 ,在初始化下载管理器时,我检查了共享路径中的目录是否存在,如果不存在,则使用createDirectoryAtPath:withIntermediateDirectories:attributes:error创建了该目录,然后再次传递了共享容器路径。 您需要执行此步骤,因为NSDocumentDirectory已经存在,但是需要创建容器目录。 既然您已使容器应用程序从共享应用程序组中写入,读取和删除数据,那么您也应该可以在iMessage扩展中自由使用它了! 当然,您的扩展程序需要数据的用途可能千差万别,但对我来说,仅对viewWillAppear进行一次检查/更新以查看文件管理器中的数据就足够了。 自从我在Swift中编写扩展名以来,我就使用了FileManager.default,并且再次使用了相同的containerURLForSecurityApplicationGroupIdentifier方法,该方法在Swift中被命名为forSecurityApplicationGroupIdentifier。 同样,您需要在“应用程序组”部分中传递确切的字符串。 然后,我过滤了结果以仅查找带有m4a文件扩展名的项目,并将这些文件保存在用于填充CollectionView的array属性中。 根据您要写入文件管理器的数据类型,这可能会变得很复杂。 但是对于我的使用,仅从写入共享应用程序组的文件和文件名中,我就能获得编写简单但有意义的扩展名所需的信息。 要考虑的一个潜在问题是您的用户在现有版本上更新到新的应用程序版本。 该应用程序的较旧版本将把数据写入NSDocumentDirectory,并且在尝试在新的应用程序组容器中查找数据时将失败。 为了获得无缝的体验,并且不让用户再次下载他们已经拥有的项目,您需要将数据从NSDocumentDirectory迁移到新的应用程序组容器。 在初始化下载管理器时,我在m4a文件格式的documents目录中添加了对项目的检查,并将其复制到共享应用程序组中,然后从NSDocumentDirectory中删除。 链接到有关使用应用程序组将NSUserDefaults共享到扩展的教程,该扩展对我有所帮助:http://www.atomicbird.com/blog/sharing-with-app-extensions

Swift用Swift编写的AST。 ∞的第4部分

在上一部分中,我讨论了let和var declrartions语法。 正如我发现的那样,语法并不能反映语言的所有语法限制。 在这一部分中,我将发现function声明的结构。 让我们从查看正式的语法定义开始: 单根声明是好的。 它还包含很多子引用,让我们更仔细地研究它们。 首先,让我们尽可能地简化这个定义。 函数头可以用其自己的内容替换,因为其定义中没有任何差异。 其次,可以通过将parameter-clause建模为[Parameter]来简化功能签名。 可以将throws和rethrows throws建模为单个可选枚举。 简化之后, function-declaration可以这样表示: struct FunctionDeclaration { let属性:[Attribute] let修饰符:[DeclarationModifier] 命名:FunctionName 让genericParamters:GenericParameterClause? 让参数:[参数] 让throwBehavior:ThrowsMo​​difier? 让结果:FunctionResult? let`where`:GenericWhereClause? 让身体:CodeBlock? } 这里有很多可选的东西。 FunctionName是第一个额外的定义。 在Swift中,函数可以表示常规方法或运算符主体。 唯一的变化是FunctionName语法。 和往常一样,我们将其建模为enum : 枚举FunctionName { 案例标识符(Identifier) case`operator`(Operator) } 现在我们将介绍Parameter定义。 单参数有3种可能的选择。 具有默认值 具有可变的长度(又称省略号) 没有修饰符的最简单形式。 换句话说,我们可以选择使用两个修饰符之一。 struct参数{ 让externalName:标识符? 让localName:标识符 let类型:TypeAnnotation let修饰符:ParameterModifier? } 枚举ParameterModifier { 大小写默认值(表达式) 省略号 } […]

使用Swift 4调整图像大小

如何在iOS中调整图片大小? 将照片调整为新的UIImage的大小:为什么要阅读此新博客? 由于存在许多博客,并且使用UIKit,CoreGraphics和CoreImage框架提供了许多示例代码。 大多数iOS开发人员都已经看到了该代码,并且可以在他们的项目中使用该代码,但是只有一些开发人员能够发现图像质量随所有这些框架而变化 。 让我们探索一种以更好的图片质量调整图像大小的新方法,您准备好了吗? 让我们使用Accelerate框架。 影像 使用CPU的矢量处理器处理大图像。 广泛的图像处理功能,包括Core Graphics和Core Video互操作,格式转换和图像处理。 进口加速 扩展程序UIImage { func resizeImageUsingVImage(size:CGSize)-> UIImage? { 让cgImage = self.cgImage! var format = vImage_CGImageFormat(bitsPerComponent:8,bitsPerPixel:32,colorSpace:nil,bitmapInfo:CGBitmapInfo(rawValue:CGImageAlphaInfo.first.rawValue),版本:0,解码:nil,renderingIntent:CGColorRenderingIntent.defaultIntent) var sourceBuffer = vImage_Buffer() 推迟{ 免费(sourceBuffer.data) } var错误= vImageBuffer_InitWithCGImage(&sourceBuffer,&format,nil,cgImage,numericalCast(kvImageNoFlags)) 保护错误== kvImageNoError else {return nil} //创建目标缓冲区 令scale = self.scale 让destWidth = Int(size.width) 让destHeight = Int(size.height) 让bytesPerPixel = self.cgImage!.bitsPerPixel / 8 […]