通常,我们的设计器会创建一些不是UIKit模式的组件。 大多数时候,我们可以做出一些改变,但有时却不能改变。 今天,我将教您如何创建自定义分段控件。 首先,让我们来一个UIKit分段控件。 在大多数情况下,我们都有边框,色调颜色和区域,我们可以自定义此分段控件。 假设您要创建此组件。 您在界面构建器中没有底视图来修改或删除所选节的背景。 让我们开始吧! 注意:我不会使用IBInspectable / IBDesignable,但是如果您知道如何使用它们,则可以。 我们的CustomSegmentedControl是UIView的子类,而不是UISegmentedControl 首先,我们需要创建变量: 我们有三个私有变量,为什么要私有? 因为我们不希望其他类可以在没有updateView的情况下更改此值。 使用默认值来自定义视图的三个变量。 现在我们需要显示按钮,但是我们有一个数组,这个数组可以是无限的。 最好的方法是创建一个水平堆栈视图 。 堆栈视图使子视图具有相等的间距,而不使用任何约束。 您如何意识到我们创建了四个约束来使我们的堆栈视图充满所有自定义视图。 现在,让我们创建选定的视图。 我们希望所选视图具有相同的按钮宽度。 我们需要用相等的部分数划分视图框架。 让我们在数组中添加一些按钮,我们该怎么做? 使用我们的buttonTitles数组。 首先,我们删除按钮中的任何元素,并删除视图中的所有子视图。 我们可以从按钮标题创建一个for,并从我们的标题创建一个单独的按钮,让我们设置标题,颜色和动作也添加到按钮数组中。 在本教程中,我考虑始终选择零部分。 让我们实现这种情况,将颜色设置为索引零的按钮。 在我们的动作函子中,我们必须创建一个用于从数组按钮中枚举的for,因为我们可以访问单个按钮和数组中的索引。 首先,我们需要将按钮设置标题颜色设置为默认颜色,之后我们需要进行比较以找到单击了哪个按钮。 我们需要找到X位置,并使用UIView.animated将我们的selectorView移到该位置,然后将按钮标题颜色设置为selectedColor 现在,我们创建一个名为updateView的功能,以调用其他三个配置功能。 很简单。 我们可以创建一个便利初始化或/和创建一个传递数组的函子。 我要创建这两个。 为什么? 因为与您一起使用的是“查看代码”,我们将使用我们的init,但是如果我们要创建IBOutlet,则需要调用函数。 如果您运行代码,它应该可以工作。 记住在viewDidLoad()中调用CustomSegmentedControl
作为软件开发人员,我们应该做的最关键的事情之一就是确保我们管理的数据是安全的,第一步应该始终是强制执行SSL加密。 这意味着任何访问您的API或老实说您的网站的人都应该使用HTTPS通过端口443对其进行访问,并在其浏览器中获得一个漂亮的封闭锁符号。 因此,在本文中,我将向您展示启动使用LetsEncrypt证书同时适用于端口80上的未加密流量和端口443上的加密流量的服务器的简单性。 首先,我从Perfect Assistant创建的全新AWS实例开始,所以我知道它拥有所有正确的功能。 接下来,我要查看https://certbot.eff.org/#ubuntuxenial-other来安装LetsEncrypt Certbot。 这将使我们轻松创建和验证证书。 按照说明进行以下操作: $ sudo add-apt-repository ppa:certbot / certbot $ sudo apt-get更新 $ sudo apt-get install certbot 在安装过程中,我将回到Perfect Assistant,并为Perfect Template制作一个新的克隆。 这将为我提供所有需要的东西的一个文件开始。 一旦克隆并构建了Xcode项目,我们将对模板的main.swift文件进行一些操作。 目前的模板具有1个HTML路由和2个“服务器”,但是我们想用2个稍有不同的服务器替换“ handler”功能。 //此“处理程序”功能用于端口80。 func handler80(data:[String:Any])抛出-> RequestHandler { 返回{ 请求,回应 response.appendBody(string:“ 你好,世界! 你好,世界!端口80 ”) response.completed() } } //此“处理程序”功能用于端口443。 func handler443(data:[String:Any])抛出-> RequestHandler { 返回{ 请求,回应 response.appendBody(string:“ 你好,世界! 你好,世界!端口443 ”) […]
IBDesignable 和 IBInspectable ,这是一种创建自定义元素和属性的方法。 可以直接将其添加到iOS Interface Builder。 此WWDC 2015视频演示了如何实现自定义UI元素。 在Interface Builder中实现UI设计– WWDC 2015 –视频– Apple Developer 突出的应用程序必须具有吸引力,直观且易于使用。 Interface Builder专家将为您提供技能… developer.apple.com IB可设计 IBDesignable属性将标识UIView或从UIView继承的元素-例如:UIButton,UIImageView,UILabel等。 例如,我创建了一个Custom UIButton类, @IBDesignable 打开类KGHighLightedButton:UIButton { 公共替代init(框架:CGRect){ super.init(frame:框架) setTitle(“ MyTitle”,用于:.normal) setTitleColor(UIColor.blue,for:.normal) } 公用必需的init?(编码器aDecoder:NSCoder){ super.init(编码器:aDecoder) } } 添加此类后,在ViewController中导入自定义类 #import KGHighLightedButton 在Interface Builder(`StoryBoard`)中,拖放UIButton。 转到“ 显示身份检查器 ”,并将类和模块设置为“ KGHighLightedButton”。 IB检查 让我们在按钮上添加一些自定义属性。 🙌 为此,我们必须使用IBInspectable属性。 让我们看看如何添加它们。 @IBInspectable public var cornerRadius:CGFloat […]
我在线上遇到了一个很棒的循序渐进教程,内容涉及如何将您的项目重组为有意义的文件夹。 可悲的是我找不到该教程了! 它解释说,对于大多数文件来说这很容易,但是某些文件需要更多注意。 这些文件是Main.storyboard和Info.plist 。 可是等等! 在继续之前,请确保您已提交COMMIT COMMIT。 在拥有干净的工作目录之前,请不要随意使用文件结构。 否则,您的所有其他提交似乎都会在此一系列已删除和添加的文件中丢失,并且没有干净的方法来查看您的实际操作。 好的,我们继续。 当您将这两个文件移到新文件夹中时,我找到了摆脱那些构建问题的方法。 我将它们移到“支持文件”中。 转到项目设置。 单击按钮“选择info.plist文件”并指定其新位置。 您想选择一个不在test或specs文件夹下的文件夹。 对于情节提要,我不确定存在什么问题。 但是,请确保已指定主界面。 如果我决定指定与Main不同的视图控制器,我想可以删除Main。 但是,请不要删除LaunchScreen。 这是您的应用在启动时查看的初始屏幕。 我认为。
在我之前的文章“如何对.ipa文件执行iOS代码注入”中,我通过概念证明展示了开发人员如何在不修改原始源代码的情况下将单个日志消息注入到iOS .ipa文件中。 由于PokemonGo应用程序最近在开发社区中的流行和兴趣,我选择了PokemonGo应用程序作为演示代码注入的目标。 这篇文章的灵感来自于PokeGo ++ mod的作者Will Cobb的作品。 可以在http://pokemongohacks.me/中找到有关他的mod应用程序的下载说明。 PokeGo ++ mod具有优雅的位置欺骗功能,已注入基础的PokemonGo游戏中。 我们将尝试为游戏创建我们自己的简单位置欺骗mod。 可以直接从iOS App Store破解原始的PokemonGo.ipa文件,然后将其安装到非越狱的手机上(敬请期待有关此内容的后续文章)。 为了简单起见,我将在一个破裂的.ipa文件上展示代码注入技术。 破裂的.ipa基本上是原始的ipa文件,其中删除了数字版权管理(DRM)。 这是您构建此mod应用程序(或修改)所需的资源 获取一个破解但未修改的PokemonGo .ipa文件。 您可以在https://www.iphonecake.com/app_1094591345_.html下载最新版本。 代码注入所需的位置欺骗代码https://github.com/depoon/InjectibleLocationSpoofing 执行代码注入的脚本https://github.com/depoon/iOSDylibInjectionDemo Cydia Impactor可以将应用程序辞职并将其侧面加载/安装到非越狱设备上。 Cydia Impactor可以从http://www.cydiaimpactor.com/下载。 由于代码注入过程和技术已在我之前的帖子https://medium.com/@kennethpoon/how-to-perform-ios-code-injection-on-ipa-files-1ba91d9438db中进行了描述,因此在本文中,我们将仅关注位置欺骗代码的内容。 只有3个文件??? 那就对了。 入侵任何应用程序的复杂性取决于您想要实现的目标以及您对iOS应用程序开发的了解。 在我们的情况下,我们只需要提供管理设备位置伪造所需的最低UI。 现在,在XCode中创建一个Cocoa Touch Dynamic Framework目标,并创建链接到该框架目标的以下类 PatchLoader(目标C) 位置Swizzler(快速) PatchUIManager(快速) 类说明 位置Swizzler.swift 进口基金会 导入CoreLocation 公共类LocationSwizzler :NSObject { static var currentLocation = CLLocationCoordinate2DMake(1.293760,103.853709)// Raffles City 静态var originalMethod:方法? […]
首先,我们必须创建自定义UIGestureRecognizer 。 我们必须认识到两个手指的移动。 在我们的识别器中,我们必须添加在触摸开始时执行的功能。 这确实是简单的功能。 现在,我们必须实现在用户移动手指时执行的功能。 在该功能中,我们将有关触摸的信息添加到两个集合中(仅当用户用两根手指触摸屏幕时)。 我们必须实现的下一个功能是当用户完成触摸时触发的功能。 在该函数中,我们必须检查用户是否做了我们期望的操作。 如您所见,这里有两个函数: twoFingersMoveUp和twoFingersMoveDown 。 在这些功能中,我们正在验证两只手指的移动,如果我们识别出移动,则以state: ended完成手势识别器。 如果我们不认识移动,则必须以state: failed 。 我验证运动的函数确实很简单(也许有点简单:-)。 我们必须实现的最后一个功能是reset功能。 该功能在用户触摸之间触发。 我们必须清理在用户触摸过程中收集的所有东西。 现在,手势识别器中已包含所有内容。 我们可以将手势识别器与控制器连接起来。 为此,我们必须在viewDidLoad函数中添加以下代码: 现在,当触摸结束时,我们的手势识别器将触发功能twoFingersGestureRecognizer 。 在该功能中,我们可以做任何我们想做的事情。 在我的情况下,我将更改主题(当用户向上移动手指时变亮或当用户向下移动手指时变暗)。 我们还有另一件事要做。 不幸的是,现在我们的手势识别器消耗了所有用户手势,因此,例如表格视图将不会对用户触摸做出反应。 这就是为什么我们必须在控制器UIGestureRecognizerDelegate添加并实现一个功能(幸运的是最后一个功能)的原因: 当然,如果要使所有屏幕具有相同的行为,则必须将该代码放在一个公共控制器中。 您可以在我的GitHub上的iOS项目中查看一下。 姆恰楚斯基/ vcoin 通过在GitHub上创建一个帐户为vcoin开发做出贡献。 github.com
在本文中,我将指导您使用SceneKit及其基于物理的渲染功能创建场景。 SceneKit是我最喜欢的Apple框架之一。 什么是SceneKit? 让我们从开发人员苹果网站查看定义: SceneKit将高性能渲染引擎与描述性API结合在一起,用于导入,操作和渲染3D资源。 与要求您精确实现显示场景的渲染算法的低级API(例如Metal和OpenGL)不同,SceneKit仅需要描述场景的内容以及想要执行的动作或动画。 从定义中可以看到,其中包含很多内容。 基本上,通过使用SceneKit,您将能够创建游戏和其他3D应用程序,而无需了解任何计算机图形算法,物理模拟等。 您基本上用对象和功能来描述场景,Apple会为您做一切。 在计算机图形学方面,关于SceneKit的最有趣的事情之一是在2016年引入的:基于物理的渲染(PBR)。 我们已经在上一篇文章中了解了PBR的含义,因此您已经了解了PBR的理论基础知识(或者在未找到go的情况下进行检查😉)。 因此,这意味着SceneKit可以使用其自己的全新基于物理的渲染引擎来渲染基于物理的场景。 这值得么? 当然!! 😊 所以,让我们尝试一下! 在本文中,我们将从头开始创建一个场景,该场景使用您可以在SceneKit中找到的主要PBR功能。 在这篇文章的结尾,您将能够渲染下图中的场景。 现在该开始编码了!! 场景构建中使用的一般方法如下:对于每个主要场景类别组件,我们将创建一个类,该类封装相应SCNNode的创建,基本SceneKit单元元素及其设置,以获取所需的功能。 。 我们要创建的第一类是 包含我们需要设置灯光的基本特征的Light类:位置,旋转和通用颜色。 使用SCNLight类表示SceneKit中的SCNLight 。 类别Light { 让节点:SCNNode init(lightNode:SCNNode){ 节点= lightNode } init(lightFeatures:LightFeatures){ 节点= SCNNode() createLight() set(lightFeatures:lightFeatures) } func createLight(){ node.light = SCNLight() } 私人功能集(lightFeatures:LightFeatures){ node.light?.color = lightFeatures.color node.position = lightFeatures.position node.eulerAngles = lightFeatures.orientation; } […]
在Slash Keyboard工作期间,内存使用一直是我们必须密切注意的事情。 通常,您的应用程序的内存配置文件是无关紧要的,因为iOS在为您管理内存方面做得很好。 但这一切都在键盘扩展中发生了变化。 键盘扩展程序基本上是作为一个应用程序运行在另一个应用程序之上的,它不会分配给它自己的内存。 相反,它与您使用的应用程序共享相同的内存池。 如果内存过紧,操作系统将优先于键盘优先应用程序。 在这种情况下,系统内存有限时,键盘的性能可能会受到影响。 幸运的是,Apple提供了一个名为Allocations的漂亮工具来帮助检测内存泄漏。 在本文中,我将介绍如何使用此工具来跟踪应用程序中的内存泄漏。 iOS中的内存使用情况 分配是Apple提供给开发人员的绝佳工具,它可以检测开发人员的代码何时导致分配内存。 在介绍如何使用此工具之前,我想先介绍一些有关为什么您可能会遇到内存问题的理论。 iOS使用所谓的自动引用计数(ARC)。 ARC将为新的类实例分配一块内存,并在不再使用该类时适当地重新分配该内存。 在Apple的开发人员文档中: 在Swift中,“内存管理“就可以正常工作”,您无需自己考虑内存管理。 当不再需要类实例使用的实例时,ARC会自动释放它们。 听起来不错吧? 在大多数情况下,是的。 但是在某些情况下,可能会导致ARC无法自动取消分配内存。 在给定的类上创建强引用循环时,会发生这种情况。 通过将一类中的变量分配给另一类中没有前缀“弱”或“无主”的变量来创建强引用。 创建后,ARC将不会释放具有强引用的任何类。 随着时间的流逝,这将导致您的内存使用量随着应用程序的使用和类的创建而增加,并且在需要时不会删除。 为了解决这个问题,我们为每个var加上“弱”或“无主”前缀,这可能会导致强大的参考周期。 这向ARC发出信号,当需要取消分配该类时,这些变量不应持有强引用。 现在,您可能不想使所有引用变得虚弱或无主,但是可能需要修复强大的引用周期。 要确定您是否有问题,请使用Xcode中的“分配工具”。 分配工具 可以在Xcode的顶部菜单中访问“分配”工具,然后选择“工具”。 或者,您可以使用热键Command + I访问运行的仪器。 注意:我更喜欢在设备上运行分配,而不是使用模拟器。 我觉得使用设备可以获得更好的效果。 进入乐器后,选择分配工具。 这是带有橙色框的那个。 如您所见,Apple提供了许多其他工具,所有这些工具本身都非常有用。 使用窗口右上角的“记录”按钮运行应用程序(同样最好在设备上)后,您正在跟踪应用程序的内存配置文件。 您应该做的第一件事是将右列设置为“ E”图标。 这将使您可以查看要签出的进程的堆栈跟踪。 在中间,我们看到一堆已经分配了内存的进程,并按分配的字节数降序排列。 忽略前三个灰色进程。 让我们检查列表中的第一个过程。 一旦我单击了流程名称旁边的小箭头(是的,它很小得令人难以置信,如果您不注意的话,很容易错过它),您将被发送到其子流程的更详细视图。 在这里,我们可以看到分配内存的各个进程。 如果在“ E”上设置了正确的窗格,则可以看到此过程的堆栈跟踪,并可以查看编译器执行哪些步骤来分配内存。 黑色的任何进程都是用户生成的,灰色的任何进程都是您无法控制的系统进程。 在此特定过程中,我的UI在主线程上进行了更新,可以占用内存。 如果我双击有问题的进程,将出现一个弹出窗口,向我显示导致内存使用的确切代码行。 重复此过程,直到您的应用程序的内存配置文件在合理范围内为止,这取决于您所创建的应用程序的类型。 尽管您可能不需要像键盘扩展那样担心内存管理,但是管理内存配置文件和提高应用程序内存的使用效率可以提高性能。 […]
前几天,当我与一个朋友谈论函数式编程时,我意识到我们经常只喜欢讨论性感的东西,而对其他简单的东西没有给予足够的重视。 在Swift中, guard声明是我认为功能非常强大但没有得到编程社区足够重视的小功能之一。 Guard不仅是if !condition语句的语法糖。 考虑以下代码。 如果!loading { 加载() } 如果当前状态未加载,它将加载。 但是我们可以更好地编写如下: 如果正在加载{return} load() 当前状态加载时返回。 它更干净,我们能够从花括号中取出load() 。 并且请注意,上面的if语句不只是if 。 如果是特殊的,用于提早返回。 它应该拥有自己的语法。 从版本2开始,Swift为此提供了guard声明。 警卫!loading else {return} load() 确保当前状态未加载,否则返回。 如果错过了return ,编译器将抱怨。 与使用if语句的版本相比,它更容易理解,因为它使用特殊的条件语法。 我们马上就知道那条线是干什么的。 警卫队要早日返回。 通常,我们将它们放在函数的顶部。 但是, guard声明并不公平,因为对我们大多数人来说,这只是一个条件声明。 但是我认为, guard应该得到更多的荣誉。 考虑以下代码。 守护!loading else {return} 警卫!渲染其他{返回} 卫队个人资料已加载其他{返回} 警卫文章已加载其他{返回} 警卫评论加载其他(返回) 守卫likesLoaded else {return} render() 以上代码在控制器中非常常见。 控制器通常是最复杂,最难阅读的。 想象一下:当控制器从服务器加载数据时,可能会发生很多事情,例如,推送通知到达,按下后退按钮,按下主屏幕按钮进入背景,设备旋转,无意间轻按了随机按钮,网络中断等等。 所有这些都应该得到妥善管理,这非常困难。 这就是为什么控制器非常丑陋的原因。 但是guard声明使它更令人恶心! […]
可测试的代码很棒。 即使您实际上没有编写任何单元测试,也可以使您的生活更轻松。 您将获得易于维护和重构的模块化结构。 到处都使用单例并不是可测试的代码。 我们经常听到人们对此表示同意,但是随后他们提出了“委托地狱”的论点。 我需要从应用程序的多层一直发送一些数据。 您是否建议我将其注入所有这些对象或使用十二个链接的委托调用? 啊! 好吧,让我们一起看看。 问题: 在这里使用共享实例并不能使我们的代码更具可测试性,清晰性或结构性,但是很容易实现: 解决方案1:共享实例 似乎链委托调用是这里唯一的选择,但是这种解决方案看起来很丑陋。 首先,链接的委托呼叫非常脆弱-您可以轻松地忘记一个。 其次,所有与主题菜单无关的对象现在也知道那里发生了某些事情。 解决方案2:链接的委托呼叫 还有其他解决方案吗? 当然! 现在的问题是,我们正在将构造责任与业务逻辑责任混在一起。 当我们需要一个对象时,我们只需在我们的类中内联实例化它即可。 我们的调用图与实例化图几乎相同。 让我们尝试将它们分开! 想象一下,应用程序下面的某些层需要一个数据库才能工作。 您可以清楚地说明此依赖性,并且您的层会在构造函数中请求数据库。 现在,它上面的一层不会说“我需要一个数据库才能将它传递给下面的层”,而是说“我需要下面的一层”! 上面的层没有关于数据库的线索。 如果您应用中某处的某个对象需要数据库,则并不意味着您需要在整个类层次结构中传递该数据库。 这是这样的: 解决方案3:工厂 最后,如果您还没有看过,请观看MiškoHevery的这场“清洁代码”演讲。