Tag: 编程

担任iOS工程师30个月。 给新人的提示。

30个月 7个应用 2个大应用 兼职自由职业者 全职iOS工程师 长期玩家 这是我给新手的iOS开发提示。 以斯威夫特 Swift vs Obj-C我应该首先学习哪个? 我的答案直接针对Swift。 使用Swift学习,播放和开始新项目。 除非您有理由使用Obj-C。 例如,维护旧应用程序。 警告-不打算在Obj-C中启动您的项目,以后再迁移到Swift。 迁移比您想象的要难。 知道生态系统 什么是流行的JSON库? 我的应用程序应使用哪个云数据库? 目前发生了什么事? 您应该了解应用程序的工具/库/框架/堆栈。 不要成为一个孤独的程序员,自己编写一切。 有人已经贡献了这些作品,使您的生活更轻松。 选择并使用它们可以提高生产率。 对于开源库。 搜索` awesome-xxx`。 例如,` awesome-swift` ,` awesome-ios` 。 使它工作,使其正确,使其快速 我一直相信这个概念。 软件开发不是一次性的工作。 好的软件是经过多次迭代制作而成的。 当您第一次做某事时,可能并不如您所想的那样好。 但是,请放心,花些时间重新访问它,并使它变得更好。 只要记住你在做什么。 经验会为您提供帮助。 下一次转到最后一步比您想象的要容易。 学习建筑 看看其他成功的应用程序。 看看它们是如何制成的。 不仅是应用程序方面,还是整个系统。 建筑角度将提高您的工艺水平。 有很多开源的iOS应用。 电报,Firefox,维基百科,WordPress,VLC,电线。 github / open-source-ios-apps是一个很好的资源。 实验 开发应用程序时。 您可能会想出很多主意。 […]

Xamarin.Mac和netstandard2

随着.NET Core 2.0的发布,今天是.NET社区激动人心的一天: 宣布.NET Core 2.0 NET Core 2.0现已作为最终版本提供。 您可以在… blogs.msdn.microsoft.com中从命令行开始使用它进行开发。 但是,如果您尝试将新的闪亮的netstandard2库与Xamarin.Mac(或iOS)一起使用,则可能会遇到一些问题,因为计划对我们的下一个主要版本d15-4(XM 3.8和XI 10.14)提供官方支持。 现在,通过安装正确的位并对csproj进行较小的调整,即可解决所有这些问题。 第一:安装在稳定频道中找到的最新d15–3版本 第二:安装.NET Core 2(您需要pkg下载) 第三:由于此错误,您需要调整Xamarin.Mac(或iOS)csproj,直到它得到修复。 将此行添加到您的参考部分: 下面 (或对于iOS,为) 但在同一个ItemGroup中。 当且仅当您针对Xamairn.Mac Full目标框架,您将需要另外添加以下行: v4.6.1 在顶部的PropertyGroup中(例如,在UseXamMacFullFramework之上)。 经过这些调整后,事情应该“正常”。 正如我提到的那样,全面支持将在下一个主要版本中进行,因此请提交遇到的所有错误。

重新构建新的App Store应用程序-Today视图

阴影 App Store应用程序中的每张卡片都有一个柔和的阴影,略微的垂直偏移使它具有深度感,并向用户建议可以轻按卡片以打开其详细的故事视图。 在当前的App Store应用中,此阴影似乎只是静态阴影。 我决定不仅要克隆此阴影,还要进一步使用Core Motion根据设备的Pitch(水平倾斜)和Roll(垂直倾斜)移动阴影。 这将以一种微妙的方式使界面感觉更生动,更丰富,类似于在tvOS界面上所做的方式。 长按手势 在当前的App Store应用程序中,每个Card视图本身也是固定的,并且不会过度交互。 您可以点按卡片以切换到“故事”详细信息视图,但不能以任何其他方式与卡片交互。 就像我可以使用tvOS界面一样,作为用户,我不得不触摸和操纵卡片,而不仅仅是点击。 我通过执行长按手势来改进此功能,该手势可以在按住卡时将其略微缩小。 这扩展了阴影创建的深度隐喻,但也不过分,以至于使卡片感觉过于灵活和不现实。 iPad网格布局 这些卡的布局会有所不同,具体取决于您是在iPad还是iPhone上查看新的App Store应用。 在iPhone上,您会看到一列垂直的卡片,其宽度和高度都完全相同,而在iPad上,您会看到两列的单元格,每个单元格将在压缩宽度和扩展宽度之间交替,以提供更多网格布局,可以更好地利用iPad的更大屏幕空间。

静态库简介

你好,世界! 今天,我将向您介绍静态库。 我们将讨论为什么使用库,它们如何工作,如何创建它们以及如何使用它们。 首先,库是编译器为我们提供的工具之一,因此我们可以将文件编译为“ .c”文件。 首先,我将讨论为什么我们使用库的原因,以及它们的重要性! 库包含几个目标文件。 当我们将’.c’文件编译为可执行文件时,它们还可以用于在链接阶段链接’.c’文件。 我们之所以使用库,是因为它有助于加速链接并使之链接,因此需要查看的内容更少。 C中的静态库起作用,因为它们是对象文件的集合,这些对象文件在链接阶段链接到程序中,并且在运行时不相关。 在运行时仅需要可执行文件即可运行程序。 创建静态库很简单。 您可以使用“ ar”(对于“归档”)创建静态库。 静态库也称为存档文件。 您可以在示例中使用C静态库,例如“ ar rc libhappy.a happy_file.o happy_net.o happy_math”。 “ ar”代表“存档”。 “ rc”中的“ r”告诉它用一些更新的目标文件替换库中的旧目标文件。 如果rc中的’c’不存在,它会告诉’ar’创建一个库。 之后,它将创建一个名为“ libhappy.a”的静态库,并将其中一个的副本放入“ happy_net.o”和“ happy_math.o”中。 总之,静态库非常有用。 我们使用库是因为它通过使用几个目标文件来帮助加快链接过程。 静态库的工作原理是,它们只是在编译过程的链接阶段链接到程序中的目标文件的集合。 我们可以使用名为“ ar”的存档命令非常简单地创建静态库。 就是这样! 这些是静态库的基础。

快速提醒Swift中的SOLID原则

如果您开始从屋顶盖房子会怎样? 墙壁易碎,倾斜角度,基础不稳定。 这样的房子寿命不长。 该应用程序具有相同的趋势,并取决于开发人员的资格。 在我们的领域中,砖是一种编程原理,对系统有不同的影响。 我认为SOLID是基本级别。 本文的目的是在Swift中提供快速指南或知识更新。 让我们用好与坏的情况来解释该缩写: 1. 单一责任 -每个对象应仅对一种责任作出响应。 换句话说,概念模块/类/结构必须响应一个动作。 单一责任-流程不畅 单一责任-流动性好 在这里,我们仅处理OrderType数据,并且可以在没有任何其他条件的情况下对其进行更改。 2. 开闭式 -实体必须开放以进行扩展,但必须封闭以进行修改。 打开关闭 –   流量不好 在我职业生涯的初期,我将更改内部功能,并且可能在数据库处理以及将现有数据相互之间导出时遇到问题。 开闭式-流动性好 更好的方法是在OrderStorage下创建子类并重写方法或准备协议,然后在OrderStorage实现正确的数据处理。 换句话说,我们无需内部修改即可扩展存储功能。 3. Liskov替换 -任何对象都可以由其子对象替换,而无需更改应用程序设置。 简单地说,如果我们将基类更改为其子应用程序,则该子应用程序将保持稳定,并且新问题不会对其他部分产生影响。 Liskov替代-流动不畅 在那里,我们违反了LS原理。 我们通过添加以下条件来更改保存功能: order.products必须具有计数验证。 基本RealmOrderStorage不会这样。 有两种解决方案: 向基类添加新参数(也更改协议) 更改NewOrderStorage类的保存接口。 Liskov替代-流动性好 在这里,我们不违反基类接口的契约,并且可以在任何地方使用新的子类代替它。 Swift的一项强大功能是面向协议的程序设计,我们可以在不进行子类化的情况下进行工作,但可以通过合同支持设计。 4. 接口隔离 -许多专用接口比一个更好。 它们既大又通用。 它有助于在使用的项目中划分功能的不同部分,并且不会在那里实现不必要的方法。 转到我们的示例: 接口隔离-流量不良 在这里,我们有几种与产品相关的其他方法。 那些没有折扣或尺寸设置的产品该怎么办? 我们可以陷入陷阱。 接口隔离-良好的流动 在这里,我们可以使用基本接口ProductType进行操作,并根据需要设计其他实例。 5. 依赖倒置 […]

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 […]

带有Sourcery的元编程Swift

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

测试Marvel的View Code项目..具有100%的代码覆盖率!

在项目中采用视图代码确实可以帮助它变得更加模块化。 几周前,我写了一篇文章,展示了如何迁移使用情节提要+ xibs构建的Marvel项目来查看代码,您可以在此处进行检查。 在那篇文章中,我描述了这样做的一些好处,其中之一就是与测试有关。 视图代码更易于测试,因此,当您采用视图代码时,您的测试服会越来越多。 今天,我将展示如何为项目编写测试以及在此过程中进行的一些重构。 您可以在此处通过测试检查存储库。 **这个Marvel的项目是在一系列的帖子中创建的,如果您错过了查看的话。 为什么测试更容易? 首先,查看代码使您可以控制代码的初始化过程。 这似乎没什么大不了,但请相信我。 现在,您可以编写一个与给定类型一起使用的自定义初始化程序,这有几个好处: 您可以在测试环境中使用setter注入,例如,提供伪造的实现(模拟)而不是真实的实现。 这可以帮助您独立运行测试,稍后再介绍。 现在,您可以控制初始化过程,您可以使用let删除一些可选参数并将变量定义为常量。 语义上更正确,比方说您正在创建角色视图控制器。 现在,您可以强制要求有人在视图控制器初始化过程中提供字符,这很有意义。 经过所有的重构和测试编写,我设法将应用程序的代码覆盖率提高到100% 。 代码覆盖率本身不应达到某个特定数字。 而是应将其用作地图,该指南显示了可以在项目中改进的地方的提示。 在某种程度上,代码覆盖率的真正价值是回答这个问题, 接下来我要测试什么? 以同样的方式,您的测试应用于重构代码并使之更好。 更好的代码意味着: 更具模块化 更可重用 封装好 明确而单一的目的 易于开发的代码 易于维护的代码 测试之所以能够帮助您“使代码变得更好”,是因为它们使您可以从接口的角度来了解代码的调用者。 如果要在后台做很多事情,通常很难测试,因此需要重构。 有无视图代码..! 现在,让我们将在早期版本的项目中使用Storyboard + xibs进行的测试与在该版本中的视图代码进行比较。 这将使我们能够检查两种方法之间的好处和区别。 使用Storyboard进行CharacterViewController测试 使用查看代码的CharacterViewController测试 您现在可以看到,使用视图代码,我们可以摆脱以前用于获取视图控制器的许多样板代码。 以前,我们无法控制初始化过程,因此我们必须从情节提要中恢复它,并重复相同的旧配方。 好吧, 不再了! 第二个版本不需要测试不是从视图控制器给出字符的情况,因为现在它是init进程的参数,这意味着如果有人想要一个CharacterViewController,他们将需要为该字符提供一个字符。在里面。 CharactersViewController测试.. 现在我们可以控制视图控制器的初始化过程了,我们可以将apiManager作为视图控制器的参数来提供,使设置器注入变得轻而易举,同时使用let可以将控制器中apiManager的变量保持不变。 在没有视图代码的先前版本中,我们必须将其保留为var进行注入,将其返回时我们无法控制初始化。 没有查看代码.. 与查看代码.. 能够控制初始化过程是如此重要,它使您可以更好地控制代码! 您可以使用下面的视图代码检查对CharactersViewController的改进测试。 CharacterTableCell规格.. characterTableCell测试也得到了极大的增强,没有视图代码,我们不得不使用cellForRow方法从数据源中恢复它,这意味着我们不得不重复同样的方法,从情节提要中加载视图控制器。 不再! […]

Swift通过Zip,Map和Reduce进行有用的操作

今天的文章是Swift中的zip,map和reduce函数。 让我们介绍一下您在编码工作中可能遇到的一个典型问题。 问题陈述 您正在使用学校评分应用程序,该应用程序允许教师监视学生的进度。 您可以获得有关班级中每个学生的信息以及他们的作业和测验成绩。 所有这些信息都可以存储并可以用JSON检索,这意味着您最终可以拥有结构化的数组和数据字典。 到目前为止,一切都很好。 但是,你的老板想要改变。 她已要求您给老师更多的方法来分析学生的表现。 尽管可以在服务器上完成此工作,但她希望看到客户端应用程序中已完成的功能以最大程度地减少网络流量以及其他一些她没有详细说明的原因。 免责声明-这是一个人为的示例,我们将简化一些假设,以使问题与zip,map和reduce上的课程一起解决。 让我们看一下如何开始使用zip,map和reduce函数来解决其中的一些挑战。 压缩 zip方法允许您使用数组,集合,字典(或符合SequenceType协议的任何类型)来从两个基础的序列中构建SequenceType 。 让我们分解一下。 SequenceType是一种协议,它允许类型使用for…in循环。 内置的收集类型是SequenceType的示例。 在下一级上, SequenceType协议定义了一个名为Generator (称为GeneratorType )的关联类型,该类型用于提供迭代功能以获得序列中的下一个Element 。 将所有这些放在一起,zip方法将创建一个对对序列,其中第i个对由每个基础序列处的索引值组成。 让我们举一个例子。 假设您有两个要相互关联的数组。 例如,您有一个学生姓名数组和一个与那些学生索引相匹配的成绩阵列。 如何创建一个将每个索引的学生和年级合并在一起的列表? 您猜对了,我们可以使用zip方法将它们组合在一起。 请参见下面的代码。 地图 每个SequenceType都有一个map方法,该方法将遍历其序列并在每个项目上调用传入的转换函数-收集结果并将其作为新数组返回。 使用map函数,可以将一种类型的数组转换为另一种类型的数组。 请参见下面的map方法签名: func map (@ noescape _ transform:(Self.Generator.Element)-> T)-> [T] 约束条件 Self:_CollectionWrapperType,Self.Index == Self.Base.Index 从前面的示例扩展,我们可以进一步格式化zip方法输出的结果以包括字母等级,并将结果转换为可通过其键访问的字典。 降低 reduce方法通过重复调用序列中的每个项目并传递一个Combine函数来累加值来返回单个结果。 func reduce (_初始:T,@noescape合并组合:(T,Self.Generator.Element)-> T)-> T 当您需要将数据点的集合煮沸成单个值时,reduce方法非常方便。 […]

雨燕:永无止境的彩虹

使用IteratorProtocol和Sequence协议创建UIColors序列 Github上的资源和游乐场 Swift IteratorProtocol和Sequence是两个功能非常强大的协议,它们允许开发人员遍历一系列值。 IteratorProtocol提供序列中的下一个值。 如果下一个值为nil,则序列将停止迭代。 它还可能包含有关迭代的状态信息。 顺序:“一种通常用于遍历for-in循环的类型”。 〜苹果。 如果您使用了Collection或for-in循环,那么您会遇到这两个协议。 但是,这些协议可以应用于集合以外的事物。 这让我开始思考: 我们还可以迭代其他一些非收集序列吗? 我想到了几个例子,最后我尝试创建一个迭代器,该迭代器生成了永无止境的UIColors序列(彩虹迭代器)。 IteratorProtocol和Sequence协议非常简单。 苹果甚至提供了两个自动包装器AnyIterator 和AnySequence ,以帮助您创建迭代器和序列。 // Rainbow迭代器和序列 扩展UIColor { 静态函数rainbowIterator(…)-> AnyIterator { 返回AnyIterator { //做一些数学运算以计算下一种颜色 return … //按顺序返回下一个UIColor } 静态函数RainbowSequence(…)-> AnySequence { 返回AnySequence(rainbowIterator(…)) } } 差不多了! 缺少的(也是最难的)是添加一种算法来查找彩虹序列中的下一个颜色。 幸运的是,Jim Bumgardner(jbum)写了一篇很棒的文章,用javascript制作了令人讨厌的彩虹,它提供了一种算法来遍历一系列颜色。 在实现了“彩虹中的下一种颜色”算法之后,我可以遍历一系列UIColors: //相移为10°的UIColors序列 let phaseShifts:[AnySequence ] = stride(from:120,through:0,by:-10).map { 让相位= $ 0.radians 返回UIColor.rainbowSequence(phase1:0,phase2:phase,phase3:phase * […]