Tag: swift

iOS面试问题第1部分:与众不同

iOS域非常庞大而深刻。 如果您正在寻找适合初学者或有经验的iOS开发面试问题,那么这里是正确的地方。 我已经准备了一些问题,并在各个部分进行了分叉,将一个故事组合在一起将无法证明该主题的合理性。 在这一部分中,我们将区分iOS中的许多已知术语。 我们遇到了许多看起来或听起来相似但略有不同或完全不同的术语。 这部分将主要关注iOS Core开发和Objective-C。 特定于Swift的术语将在单独的部分中进行讨论。 🙂 问:@合成VS @动态 @ synthesize将在编译时为您的属性生成getter和setter方法。 @dynamic只是告诉编译器,getter和setter方法不是由类本身实现的,而是由其他地方实现的(例如超类或将在运行时提供)。 @dynamic的用法例如与NSManagedObject (CoreData)的子类一起使用,或者当您要为由超类(未定义为插座)定义的属性创建插座时。 问:XIB VS NIB XIB(XML Interface Builder)是Xcode中的可执行代码。 它的大小比笔尖大。 这些是平面文件和XML文件 NIB(Nxt Interface Builder)是不可编辑且不可操作的文件。 它们的尺寸较小。 这些是二进制或存档文件。 编译后,XIB转换为NIB。 问:NSInteger VS Int VS NSNumber NSInteger是一种描述整数的类型定义,但它并不等效于64位平台上的int 。 在构建32位应用程序时将其定义为int ,对于64位应用程序则将其定义为int 。 大多数情况下,您可以使用NSInteger替换int,但这样做时需要考虑一些事项。 Int是原始数据类型。 NSNumber将数字类型存储为对象,并且可以转换为其他格式。 它还可以检索字符串表示形式。 问:任何VS任何对象 根据Apple的Swift文档: Any 可以代表任何类型的实例, 包括函数类型和可选类型。 AnyObject 可以代表任何 类类型 的实例 。 查看更多详细信息。 […]

Swift:类型推断

我要坦白。 我真的对在我的代码中各处编写iflet和guard感到厌倦。 我看到一些真正的基本问题: 您正在与Swift斗争,而不是表达需要完成的工作; 您没有到强制转换代码的中央访问点; 您对Swift API的更改不满意。 您必须编写更多代码,自动完成功能将无法为您节省$ 您不使用类型推断。 首先,让我介绍一下我使用的强制转换功能: 是的,那只是上面的包装? 。 为什么好呢? 它允许在不考虑Swift的预处理限制的情况下转换为类型,而Swift的预处理限制仅出于帮助开发人员的原因而创建,这些限制对类型一无所知。 一个很好的例子是Int? 要转换为Int?的类型(是的,可选的包装在可选的包装中,您没有误读)。 猜猜是什么,编译器不会让您用as那样做? : 编译器失败,并从’Int ?? 到“诠释?” 仅解包可选; 您是要使用’!’吗? 。 这意味着,编译器可以做到这一点,但是,它认为它更了解程序员想要什么,因此它试图通过强调,通过展开Int来提供帮助。 进入Int? 我们收到Optional 作为结果。 哦,非常感谢你,Obvious上尉,没有您的宝贵帮助我们就无法猜到。 因此,另一种解决方案是使用泛型类型。 您可以从Swift本身的角度(如果我们可以禁用程序员的健全性检查)来看,泛型中的类型可以是任何类型,包括函数,可选,数组或其他任何类型。 而且,你猜对了, 诠释? 以及诠释? 也是分开的类型。 而且, 作为? 本身可以用于解包(尽管我理解为什么强制转换可能导致解包的原因,而AST和SIL都没有提供这种行为的任何线索)。 因此,如果我们看一下上面的强制转换函数,是否要强制转换并从Int中解包? 输入Int? ,我们可以这样写: 这将向我们显示:Optional(1)。 另一方面,如果我们尝试转换Int? 转换为Int类型的系统将按预期方式运行,并且不会打印任何内容: 但是,这种功能尽管是类型推断(启用并可链接),但就您必须编写的代码量而言,并不是特别有用。 可以通过使用函子,应用函数或单子函数来缓解这种情况。 我可以承认,我正在迈入函数式编程的第一步,因此,在设法掌握FP背后的思想以及如何将它们与OOP可变状态混合后,我将在以后的博客文章中介绍这些类型。在一个友好的功能社区的帮助下(对所有的lispers和haskellers表示敬意,他们回答了我的愚蠢问题,并编写了免费的开源书籍,以简单的方式解释了困难的概念,你们是最棒的,伙计们)。 现在,让我们以简单不正确的方式定义这些类型: Functor —类型,谁实现地图 ; 适用性-类型,实施者; Monads —类型,谁实现flatMap 。 […]

Swift片段#8-收藏

您可以在这里找到其要点 ! 上面的代码片段使以集合方式访问after和before元素变得更加容易🚀。 如果后续元素不存在,则仅返回nil 。 让我们看看它的用例。 如果您想知道Swift-Snippets的诞生,或者想查看更多此类片段,可以在这里找到它们find

使用Alamofire和EVReflection自动映射和解析JSON

我经常使用Alamofire进行HTTP联网,这是用Swift编写的流行联网库。 因此,它是极其强大的库,易于使用,但是在进行网络操作时,我经常需要抽象层来封装Alamofire而不是直接调用它。 我在过去的项目中确实使用Moya作为抽象,所以基本上,它提供了Manager类来定义端点,请求参数等的明确用法。因此,我确实创建了自己的Manager单例来管理这些东西。 在设计模型时,我们需要为每个请求的JSON值实现映射,并为我的模型实现响应周期 ,但是如果响应JSON结构经常更改(需求可以快速更改,可以快速转换请求/响应),那将是痛苦的。 我以前有在Swift中使用Reflection的经验,所以确实有机会在新项目中尝试EVReflection。 什么是EVReflection? EvReflection是一个带有反射功能的Swift帮助程序库,该功能支持NSCoding,Printable,Hashable,Equatable和JSON。 将基于NSObject的对象解析为字典。 将字典解析回一个对象。 从字符串值创建一个类并获取一个类的字符串值。 支持NSCoding方法encodeWithCoder和decodeObjectWithCoder 使用所有属性时,支持可打印,可哈希和等于。 (支持Swift 1.2中的Set) 将对象解析为JSON字符串,并将JSON字符串解析为对象 从EVReflection中裁剪 实施请求/响应模型 首先,我们需要设置从EVReflection(EVObject)基类继承的请求/响应模型。 适用于所有请求的BaseRequest,适用于应用程序中所有响应的BaseResponse以及用于解析错误JSON结构 (如果存在)的ErrorResponse (如果接收到用于警报,通知等的错误响应对象) 因此,如果JSON中包含错误有效负载以进行映射,则需要对其进行解析。 我们可以传递额外的默认值,例如应用程序的当前版本,内部版本号或任何其他数据。 然后,在下面的示例中,我们可以简单地声明从BaseRequest / BaseResponse类继承的Request / Response模型。 因此, 从EVObject继承的模型将自动进行映射 。 另外,如果您需要使用某些值作为请求/响应,我们可以通过实例化类来设置默认值 最后,定义一个采用请求参数(BaseRequest)和完成处理程序响应(BaseResponse)的方法为我们提供了完成处理程序。 (我们也可以在此处进行网络状态检查等。) 好处 我们不需要为模型编写映射或为JSON响应(以及请求)使用某些映射库。 我们确保正确定义了请求/响应周期 ,我们完全知道请求的内容,并且知道响应应该做什么。 我们确实使用可达性检查了网络状态 (您可以自己实施) 我们通过Alamofire的validate()方法确保它是经过验证的响应。 它会自动验证 200…299 范围 内的状态码 ,并且如果提供的话,响应的Content-Type标头与请求的Accept标头匹配。 我们有AccountResponse(BaseResponse)和错误(如果有)作为响应 我们使用了AlamofireJSONToObjects库, 该库使用EVReflection (作为Alamofire扩展名) 将JSON响应数据转换为Swift对象 。 我们拥有干净,可测试的实现,可以重复使用以支持不同的API请求。 这是创建请求的示例方法 […]

每周iOS Swift开发新闻#3

我将在本周最热门的图书馆,文章,工具和教程中谈论与我们钟爱的编程语言:Swift相关的事情。 RXVIP:干净的主动架构: 通过安德鲁·麦克卡鲁斯(Andrew Mackarous) 在Swift Dev News#1中,我给了您一个指向Clean Swift的链接,Clean Swift是Swift的干净架构,也称为VIP。 好吧,本文是关于将Clean Swift(VIP)与Reactive Swift(RxSwift)结合使用的。 我对RxSwift并没有那么丰富的经验,但是我对RxSwift所做的一切使我注意到它的功能强大,然后与Clean Swift架构混合在一起…… 移动应用内购买优化的终极指南: 由Hady Elhady 开发应用程序时,我们要发布的主要原因之一是对社会产生影响,并使生活更轻松,这是一个好的应用程序的含义,但是还有其他目标需要实现。 我们在谈论金钱。 在本文中,您将学习如何吸引用户并使他们想在您的应用上花钱。 什么样的功能可以销售,订阅,删除广告,限价促销,捆绑销售……如果您想知道用户希望在应用内购买中看到什么,那么本文适合您。 如果您做得不错,并且拥有一些kickass高级功能,并且玩得好,您的用户将像这样: 完美的Swift:使用Swift的服务器端: 这类似于Vapor,是供开发人员使用Swift编程语言构建应用程序和其他REST服务的Web服务器和工具包。 您可以使用Swift进行所有操作 Swift 4.1更改摘要: 通过HackingWithSwift Swift 4.1通过keyDecodingStrategy改进了Codable Swift 4.1的新功能 Swift API设计指南: 来自swift.org的Swift编码的良好做法。 自动布局天堂的五个步骤: 通过艾格尼丝·瓦萨尔海里 我个人不喜欢以编程方式使用约束,但是本文说明了如何通过五个简单步骤来掌握约束。 也许您不喜欢以编程方式使用约束,但是本文值得一试。 查看Agnes Vasarhely谈论的关于避开安全区域的部分。 PodsUpdater: 通过Kizito Nwose 当您想更新Pod或获取特定版本时,您必须编辑Podfile,使用此OSX应用程序,您将拥有一个更好的UI。 当然您可以使用终端来做到这一点,但是毕竟我们除了可以使用终端之外,还使用SourceTree。 ARKit增强现实简介: 由KárolyNyisztor 本教程说明什么是增强现实,以及如何使用Apple的ARKit检测飞机并在第一个ARKit应用程序中使用3D对象迈出第一步。 创建自定义Xcode项目模板: 通过useyourloaf.com 如果您想创建自己的模板,而要使用空白页,标签页或单页,则本教程将通过简单的方法进行说明。 卡彻: 通过MountainBuffalo 这是另一个缓存库,但是完全在Swift中。 […]

iOS中的MVP设计模式

我确定您已经熟悉MVC,但是您也感到有些痛苦,例如: 难以在View和ViewController上进行测试 Viewcontroller处理一切时变得越来越大 今天,我要谈谈另一种架构模式MVP 。 什么是MVP 模型视图呈现者(MVP)是模型视图控制器(MVC)架构模式的派生产品,主要用于构建用户界面。 —维基百科 这里的被动视图部分包括视图和视图控制器。 该模型是放置数据的地方,并定义了处理该数据的逻辑和计算。 view(view + viewcontroller)是一个被动界面,可以简单地显示数据,并接收将其处理的用户动作呈现给演示者。 演示者是模型和视图之间的中介者。 所有演示逻辑都应放在此处。 代码说明 //模型 优点 降低代码复杂度 易于执行单元测试 视图控制器不再庞大

如何在Swift中应用单一责任原则

有时,当我们学习编码时,很难理解类责任的概念。 这是因为我们的第一个项目变得难以维护,原因是我们的代码中按类包含许多行,更重要的是,它承担了许多责任。 真正了解类责任的一种好方法是考虑可伸缩性。 让我们看一个如何使用它的例子。 但是,在此之前,我想先介绍一些理论并解释为什么这个概念在软件设计中很重要。 每个类在软件项目中负有单个责任的思想,并且将责任封装在一个唯一的类中的想法有一个名称:单一责任原则 这是SOLID软件设计的5条主要原则之一,他们在面向对象编程中尝试定义一个指南,以拥有更易懂,灵活和可维护的软件。 这些原则是: 单一责任原则 开闭原则 里斯科夫替代原则 接口隔离原理 依赖倒置原则 这些概念的作者Robert C. Martin(他写了软件体系结构中最重要的书之一,即Clean Code)谈到“一类应该只有一个改变的理由” ,因此他将责任定义为更改。 例如,让我们考虑一个编译并打印报告的模块。 想象一下,可以出于两个原因而更改这种模块。 首先,报告的内容可能会改变。 其次,报告的格式可能会改变。 这两件事因不同的原因而改变。 一种实质性和一种化妆品。 单一责任原则说,问题的这两个方面实际上是两个单独的责任,因此应该放在单独的类或模块中。 耦合由于不同原因在不同时间发生变化的两件事,将是一个糟糕的设计。 使班级专注于单个关注点很重要的原因是,它使班级更加强大。 继续前面的示例,如果更改了报表编辑过程,则存在更大的危险,即如果打印代码属于同一类,则该打印代码将被破坏。 (示例摘自 Wikipedia ) 如果我们定义班级,知道他们在项目中的职责是什么,我们可以: 轻松了解其在代码各部分中的功能。 更快,更详细地修改现有逻辑。 以较少的问题查找错误或有害行为的来源。 不同类或模块中的抽象逻辑。 拆分时没有重大问题的实现,因此以后可以完全替换它们。 通过类或模块以更有效的方式定义单元测试,因此我们可以测试一小段代码,而无需测试更多的代码。 正如我之前说过的,您可以在类中考虑可扩展性以定义职责。 这就像思考是否可能在我们的项目中修改需求并在我们的体系结构中查看如何进行这些修改一样简单。 例如,如果我们看到要进行小的视图更改,则必须修改或修改业务逻辑,则我们没有正确定义项目中的职责。 让我们看一下Swift中的一个具体示例。 假设我有一个应用程序,它显示了商店中的商品列表。 到目前为止,我只有一个ItemsViewController负责该流的所有逻辑,数据和表示。 同样,当用户选择一个项目时,它也会打印日志。 您可以在https://github.com/fedejordan/SRPExample中查看代码 为此, ItemsViewController使用UITableView在列表中显示项目。 另外,我们使用一个名为ItemTableViewCell的UITableViewCell子类来显示这些元素。 但是,假设我们要更改视图,例如,使用UICollectionView. 在这种情况下会有什么问题? 视图代码与项目数据逻辑非常耦合。 如果我们更改视图,则很有可能也会修改负责该项目的类。 真正的问题在于以下几行: 让item […]

Swift-适用于iOS 11大标题的自定义导航栏图像🎨

标准的iOS组件可能会很无聊……幸运的是,有了Swift,自定义随处可见! 本文将演示如何在导航栏中使用自定义图像,同时仍保留导航控制器中提供的所有功能。 🚀 TL; DR :使用少量代码清除导航控制器提供的默认导航栏图像,并将其约束在视图的顶部,前导和尾随锚点上,以将其放置在适当的位置(请确保不要约束到安全区域) 。 您可能需要手动创建可能是您要记住的自定义导航栏标题。 有很多方法可以做到这一点,但最简单的方法就是使用Sketch。 使用矢量工具,我能够在几分钟内创建出我想要的设计。 这里的尺寸并不重要,因为Sketch默认具有出色的导出预设(iOS预设提供标准的Xcode要求的@ 2x和@ 3x大小)。 假设您已经在导航控制器中嵌入了视图控制器,则下一步是从提供的默认标题图像中剥离导航栏。 这相当简单,可以用几行代码来完成。 这是我用来执行此操作的功能; 请注意-我将其用作重用的struct ,但这是可选的。 既然导航栏已经清晰了,我们就可以提供自己的图像了。 出于本文的目的,我将使用界面生成器来完成此操作。 这就像将UIImageView拖到视图控制器上,提供适当的图像并设置约束一样简单。 为了设置约束以使iPhone X不会裁剪图像,我们需要约束imageView的顶部锚点以view的顶部锚点(而不是安全区域)。 在我的情况下,将约束设置为0在边缘沿边缘留一个小间隙,因此值-2应该可以解决该问题。 当然,高度限制将根据所使用的图像而变化。 并且,由于我的图像较暗,因此我还将大标题文本的颜色设置为白色,并将状态栏设置为.lightContent 。 此时,自定义标头应按预期工作 您可能会注意到标题图像在iPhone X上看起来不错,但在其他任何设备上看起来都太大了。 这是因为view的顶部锚点和X上的view的顶部安全区域锚点之间存在间隙。幸运的是,可以通过IBOutlet引用轻松地调整图像的高度,以参考图像视图的高度约束。 完整的设备尺寸可在此处找到。 将此代码放在同一区域,我们清除导航栏默认图像: 您可能还会注意到,将设备旋转到横向时,标题图像的高度过高。 这可以通过视图控制器中提供的willTransform(to:with)方法轻松处理。 我没有在示例中包含它,但这也可以在导航栏中添加栏按钮项。 而已! 您的自定义导航栏图像现在应该可以正常工作work 随时在Twitter和Github上关注我,以获得更多类似this‍👨🏻的内容

不要依赖临时状态

上一次,我们讨论了构建iOS单元测试的四个简单规则。 我真的很想把所有要做的和不要做的事情放在一起写在一篇文章中,但是阅读起来实在太大了。 所以这是硬币的另一面。 关于您应避免的所有事情的系列文章。 信不信由你,完全有可能编写弊大于利的单元测试 。 在本文中,我们将研究一种依靠临时状态来弄乱单元测试的特殊方法。 什么是临时状态? 如果在使用您的应用过程中可能发生变化,那么就定义而言,这是暂时的或偶然的。 每个应用程序都会在内存或磁盘上存储某种临时状态。 许多应用程序从服务器检索临时状态。 每次您从某个可以写入的位置访问数据时,您都在访问临时状态 。 数据会随着时间变化。 今天得到的可能与明天得到的不一样。 Facebook上的用户可能会说他今天喜欢滑雪,但是明天他会说他喜欢滑雪。 他的爱好是暂时的。 您不能依靠它们随着时间的推移而变得相同。 如果您从服务器上检索他的业余爱好数据,则无法确定会得到什么。 单元测试绝不应依赖临时状态 。 它使他们变得善变。 如果有一天运行它们,它们将提供一个结果。 改天运行它们,它们会产生不同的效果。 单元测试应该是确定性的 这样,我的意思是每次您运行它们时,它们都应始终提供一致的结果。 确定给定单元测试是成功还是失败的事情不应是可能改变的外部事实 。 它应该是您的应用程序所依赖的核心逻辑。 如果单元测试依赖于用户默认设置,本地文件或服务器的响应,则它们不再是确定性的。 这是因为它们的成功或失败不仅仅取决于逻辑本身。 结果,您将无法非常有效地将单元测试用作诊断工具。 您如何知道代码或某些临时状态是否导致给定测试通过或失败? 你不会的 可能永远是。 这种无法确定测试成功或失败原因的能力有时称为脆弱性 。 不稳定测试是由于与被测试代码不直接相关的原因而给出不同结果的测试 。 您绝对想避免这种情况。 这是片状测试的实际外观 假设您有一个应用程序,其中登录用户可以访问某些功能列表。 您可以通过以下方式实现访问授予机制。 如何修复片状单元测试 问题在于缺乏抽象。 shouldGrantAccessToFeatureWith(id 🙂需要知道用户是否已登录,可以通过直接转到用户默认值来进行登录。 如果将相同的逻辑重构为可以被子类覆盖的函数该怎么办? 在编写单元测试时,请始终问自己,该测试采用什么逻辑? 测试逻辑,然后抽象其他所有内容。 下一步是什么? 我目前正在阅读一系列文章,详细介绍在为iOS编写单元测试时应避免的一些体系结构方面的内容。 下一篇文章深入探讨了避免副作用。 目前,您可以了解我的其他一些单元测试内容 我们应该在iOS应用程序中进行哪些单元测试? […]

Swift中的JSON(De)Serialization

现在,我已经启动并运行了Node.js服务器,接下来我将继续研究应用程序的客户端。 我必须解决的第一个任务是进行API调用和处理JSON响应。 在本文中,我将引导您完成代码以完成此任务。 第一步是创建可JSONifiable的类。 值得庆幸的是,很多功能是预先内置在swift中的。 在这里,我将使用JSONEncoder和JSONDecoder处理对象的序列化和反序列化。 我添加了两个函数来封装它,encode()可以将一个对象转换为可以传输到服务器的JSON数据,decode()可以将数据转换为Swift对象。 您可以在下面看到如何使用它的示例。 下一部分将使用此Transmittable协议使用JSON主体对服务器进行API调用,并接收和处理响应数据。 这个APICaller类的主要功能是对服务器上的端点执行API调用。 该函数采用一个端点(“ / users”),一个方法(“ POST”),一个请求主体(一个User对象)以及响应类型(User.self)。 它调用createURLRequest()来格式化URLRequest对象。 然后,它使用URLSession调用后端。 接下来,我们检查HTTP响应代码。 除200(或200s之外的其他任何代码)之外的任何代码均表示呼叫成功通过了网络,但是服务器引发了错误。 如果所有检查都通过,我们将反序列化服务器返回的数据并调用完成处理程序。 在上面的示例中,我们使用User对象主体对/ users端点进行POST调用。 在这种情况下,我们还将在服务器的响应中返回User对象。 希望这对您的项目有所帮助。 始终欢迎提出问题,评论和更正。