Tag: iOS应用程序开发

适用于应用程序开发人员的最佳iOS开发播客

这个故事最初发布在 Apps-Top.com上 如果您是iOS应用程序开发人员,或者只是想了解有关iOS和Swift开发的更多信息,请随时关注最新的iOS开发新闻并收听新的采访,则可以查看并订阅这些播客。 在我们的列表中,您将找到20多个针对iOS开发人员的播客。 最佳iOS开发播客: 在雷达波涛下 Under The Radar播客是关于独立应用程序开发的。 永远不会超过30分钟。 独立开发人员和iOS开发人员的绝佳播客。 现场 iTunes播客 Rss 主持人: David Smith,Marco Arment 出:每周 在IOS DEV PODCAST内部 在iOS开发人员内部播客是每周一次的有关真实iOS开发的节目。 这是专业iOS开发人员的表演。 现场 iTunes播客 Rss 主持人:亚历克斯·布什,安德鲁·罗恩 出:每周 iOS开发BREAK iOS开发中断播客,为iOS开发者提供15分钟的最新事件,提示和建议! 包括但不限于Swift,iOS,watchOS和tvOS开发的讨论。 现场 iTunes播客 Rss 主持人:埃文·斯通 出:每周 SUNDELL的SWIFT Swift由Sundell Podcast制作。 iOS开发人员John Sundell介绍了Swift开发技术,框架以及提示和技巧。 现场 iTunes播客 Rss 主持人:约翰·桑德尔 外出:每周或每月 不仅仅是代码 关于iOS和Mac开发人员进行的移动开发的展览。 现场 iTunes播客 Rss 主持人: Tim Mitra,Jaime […]

迅捷属性

什么是属性? 属性将值与特定的类,结构,枚举关联。 属性类型? 商店属性。 计算属性 商店属性规则。 它可以存储常量(let)和变量(Var)作为实例的一部分。 它只能使用类和结构。 注意:我们可以在store属性上提供默认值,并且可以在初始化期间为store属性修改初始值。 例:- struct FixedLengthRange { var firstValue:Int 令长度:整数 } var lengthOfrange = FixedLengthRange(firstValue:0,length:3) //范围代表整数值0、1和2 lengthOfrange.firstValue = 6 //范围代表整数值0、1和2 在这里,FixedLengthRange类具有名为firstValue的变量存储属性和名为length的常量存储属性,其值不能更改。 常量结构的存储属性。 如果我们创建结构的实例并为其分配常量。 这样我们就不能修改属性的实例,即使它们被声明为变量属性。 例:- 让 rangeOfFourItems = FixedLengthRange(firstValue:0,长度:4) //此范围代表整数值0、1、2和3 rangeOfFourItems.firstValue = 6 //即使firstValue是变量属性,这也会报告错误 计算属性规则。 1.可以定义类,结构和枚举 2.它提供一个getter和一个可选的setter,以间接检索和设置其他属性和值 如果在属性声明中将属性定义为get {},则会将该属性变为计算属性。我们可以使用两种类型的计算属性,一种是在属性内部使用get {},也可以同时使用get {}和set {} 。 如果我们将属性定义为get {},则称为只读计算属性。 例:- 使用get {} var […]

NS for iOS Devs —查看生命周期

在 Swift Post 上以更好的格式阅读此文章 。 在学习了应用程序生命周期之后,视图生命周期在每个iOS开发人员的生命中都占有重要地位。 每个视图都是使用情节提要,XIB或编程方式创建的。 与方法无关,真正了解创建,加载,出现或销毁视图的时间有助于我们在开发屏幕设计,动画甚至业务逻辑时深刻理解我们的方法。 好的,但是为什么我们需要知道? 当我们考虑应用程序的生命周期时,我们很容易看到,随着应用程序进入后台,挂起等状态,某些事情正在发生。每当用户与应用程序进行交互时,就会发生某些特定的操作,并且应用程序的状态可能会发生变化。 但是,视图的状态可能会随着用户交互或应用程序数据的任何变化而改变。 另一方面,当视图中存在某种状态转换时,我们可能需要操纵用户界面。 例如,如果我们要使用自定义视图并将其设置为UIViewController的视图,则必须在loadView方法中进行操作。 或者,如果我们的设计要求我们在横向和纵向模式之间有微小的差异,那么我们需要知道何时可以在代码中进行此更改。 因此,了解所有生命周期方法不仅可以帮助我们编写代码,还可以使我们更具创造力并实现高级用户界面。 我们需要知道些什么? 为了在适当的位置使用视图,我们需要知道何时创建,加载,显示,更改,消失和终止视图。 UIViewController子类负责管理视图(又称UIView )。 视图控制器具有一个根视图,它是一个UIView实例。 这里重要的是它们如何一起工作。 UIViewController处理UIView背后的所有魔力,而UIView只是向用户显示屏幕和某些内容。 UIViewController告诉根UIView对象何时进入屏幕。 首先,视图控制器创建其根视图并加载它。 加载后,它告诉视图出现在屏幕上,并在必要时消失。 此外,一个视图控制器可能是另一个视图控制器的子代。 因此,视图控制器的生命周期不仅关心其根视图,而且还包括与其他视图控制器的关系,就像它是否移至父视图控制器一样。 最后,视图控制器的根视图(也称为UIView)具有自己的内容和生命周期。 根视图具有其子视图,例如按钮,标签,开关或其他UIView子类。 在大多数情况下,并不是每个开发人员都考虑子视图的生命周期。 但是有一种常见的情况是将视图控制器嵌入另一种情况。 在这种情况下,我们需要为两个视图控制器的视图模仿生命周期操作,并在必要时调用适当的方法。 我们如何获得有关生命周期事件的通知? UIViewController有很多方法可以在发生某些特定操作时通知我们。 例如,我们可以重写viewDidLoad方法以在加载视图后立即执行一些操作。 或使用loadView方法将UIViewController的根UIView替换为我们的自定义UIView类。 我们将研究视图和视图控制器的组合之间的关系,以了解当前状态。 与其过多地关注每种方法的作用,不如介绍每种方法的重要意义以及何时使用它们。 UIView — UIViewController关系 loadView :这是加载视图控制器的根视图的位置。 view , UIViewController view属性为nil 。 如果要创建自定义视图并将其设置为view属性,则需要重写此方法。 如果使用Interface Builder创建视图和初始化视图控制器,则不得重写此方法。 重写此方法后,我们必须初始化自定义视图并将其设置为UIViewController view属性,并且永远不要调用super.loadView因为它自己创建视图并分配给view 。 最后,我们不应该直接调用此方法。 […]

Swift中的“变异”

众所周知,类是引用类型,而结构和枚举是快速的值类型。 这意味着类对象共享该对象的单个实例,并在传递给任何函数或新对象时传递相同的引用,而值类型是创建其副本并仅传递值的类型。 如果我们尝试更改类中的任何变量,那就很简单。 班级员工{ var名称:字符串 var teamName:字符串 init(name:String,teamName:String){ self.name =名称 self.teamName = teamName } func changeTeam(newTeamName:String){ self.teamName = newTeamName } } var emp1 = Employee(name:“ Suneet”,teamName:“ Engineering”) print(emp1.teamName)//工程 emp1.changeTeam(newTeamName:“产品”) print(emp1.teamName)//产品 而如果您尝试在任何值类型中执行相同操作,则会向我们显示编译错误, struct Employee { var名称:字符串 var teamName:字符串 init(name:String,teamName:String){ self.name =名称 self.teamName = teamName } func changeTeam(newTeamName:String){ self.teamName = newTeamName //无法分配给属性:“ self”是不可变的 } } 它会向我们显示以下错误 无法分配给属性:“自我”是不可变的 […]

IOS APP的VIPER体系结构优势

众所周知,软件行业的软件体系结构至关重要。 设计代码很重要,这样每一部分都易于识别,具有特定目的并以逻辑方式与其他部分组合在一起。 它应该易于维护,可扩展并具有高质量。 在开发iOS应用时,请务必考虑应使用哪种iOS项目架构。 大多数开发人员使用Apple建议的模式。 但是还有其他! 在本文中,我们将研究VIPER体系结构,它是MVC的一种流行替代方案,它可以帮助您克服其限制,同时保持代码的组织良好,从而改善开发过程。 VIPER是View,Interactor,Presenter,Entity和Router的反义词。 此体系结构基于“单一职责原则”,这导致了干净的体系结构,从而为您的iOS项目提供了更好的结构。 让我们详细了解每个字母的含义: 视图。 视图的职责是将用户操作发送给演示者,并显示演示者告诉其的内容。 交互器。 这是应用程序的骨干,因为它包含应用程序中用例描述的业务逻辑。 交互器负责从模型层获取数据,并且其实现完全独立于用户界面。 主持人。 它的职责是根据用户操作从交互器获取数据,创建一个视图模型实例,并将其携带到视图中以进行显示。 实体。 它包含Interactor使用的基本模型对象。 它具有其他体系结构中模型层的部分职责。 路由器。 它具有用于描述何时显示哪些屏幕的所有导航逻辑。 在Viper架构中,每个块对应一个具有特定任务,输入和输出的对象。 这与装配线中的工人非常相似:一旦工人完成了对某个对象的工作,该对象就会传递给下一个工人,直到完成产品为止。 块之间的连接表示对象之间的关系,以及它们之间传递的信息类型。 从一个实体到另一个实体的通信是通过协议给出的。 这种架构模式背后的想法是隔离应用程序的依赖关系,以平衡实体之间的职责委派。 基本上,Viper架构将您的应用程序逻辑划分为较小的功能层,每个功能层都有严格的预定义职责。 这使得在层之间的边界处测试交互更容易。 它非常适合单元测试,并使您的代码更可重用。 简化复杂的项目。 由于模块是独立的,Viper非常适合大型团队。 使它具有可伸缩性。 使开发人员能够尽可能无缝地同时进行处理 解耦代码以实现可重用性和可测试性 根据角色划分应用程序组件 设定明确的责任,Viper是责任分配的倡导者 轻松添加新功能 由于您的UI逻辑与业务逻辑分离,因此使编写自动化测试变得容易 它鼓励将关注点分离开来,从而更容易采用TDD。 Interactor包含独立于任何UI的纯逻辑,这使得测试驱动变得容易 易于使用 创建清晰且定义明确的界面,独立于其他模块。 这使更改界面向用户呈现各种模块的方式变得更加容易。 借助单一责任原则,可以更轻松地通过崩溃报告跟踪问题 使源代码更清洁,更紧凑和可重用 减少开发团队中的冲突数量 适用SOLID原则 减少合并冲突的次数 您可能想要先创建初始体系结构框架,然后再将模块逐个交给其他开发人员以实现逻辑。 使代码库看起来相似。 阅读他人代码变得更快。 Viper架构具有很多好处,但必须指出的是,最好将其用于大型和复杂的项目。 由于涉及的元素数量众多,该体系结构在启动新的小型项目时会产生开销,因此对于不打算扩展的小型项目而言,Viper架构可能会显得过大。 因此,对于此类项目,最好使用其他内容,例如MVVM。 […]

跳过并保存为Apple Watch

今年10月,我将使用了3年的0系列Apple Watch升级到了带有LTE的新3系列,我喜欢它。 我在过去三年中一直佩戴原始手表,并且发现新模型在速度和准确性(尤其是Siri)方面取得了巨大进步。 心率传感器得到了改进,电池寿命也很棒(即使在锻炼和打电话时会受到重击)。 我很被打扰,不得不为此做点事情。 自从发布我的上一款游戏,即用Swift制作的Ultra Dash之后,我便过渡到在Unity中开发所有游戏。 这是有道理的 a)我可以使用多平台 b)关于Unity的支持/教程/帮助太多了 c)它使3D开发非常容易。 但是应用程序与游戏不同,因此我觉得从技术上讲,我并没有违背自己对专注于Unity进行游戏开发的承诺🙂 那么这个程序是什么呢? 它被称为“ 跳过并保存” ( Skip and Save) ,是我习惯于放弃偶尔省钱的习惯而生的,以便以后可以购买更大的东西。 我知道,这是一种狡猾的预算方式,但对我有用。 我认为这将是一个转化为应用程序的好过程,对于Watch来说,这似乎也是完美的选择,因为最好的应用程序是基于有限的交互(不超过几秒钟)而实现的。 构建手表应用 Xcode中的Watch应用开发环境非常好。 布置一个应用程序非常容易,比布置一个iPhone应用程序要容易得多,我以后会发现。 现在,您可以将SpriteKit和SceneKit与常规屏幕混合使用。 当您成功跳过并节省金钱时,我用它来添加股票行情带效果,并在达到目标时为烟花效果增光。 我想尽可能多地使用Watch,所以我增加了Siri语音识别,Scribble支持以及对Watch的所有不同复杂功能的支持。 我还确保手表可以与iPhone版本来回通信。 该应用程序的第一个版本使用强制触摸来访问选项以设置您的储蓄目标并重置进度或撤消跳过。 根据我在其他Watch应用程序上的经验,我发现这非常不直观,并且经常隐藏关键功能。 因此,我尝试使用一个页面应用程序,用户可以滑动到其他页面以查看更多命令。 这在实践中也不是一件好事。 我决定使用一个屏幕应用程序,其中包含一个按钮来显示设置目标,撤消跳过和重置进度的选项,以及另一个信息按钮来显示目标。 我还尝试了一些按钮的图像,并选择了自己的设计和Font Awesome 5集的设计。 构建iPhone应用程序 尽管我非常喜欢Watch,但事实是,仅Watch应用程序的市场仍然很小,因此我需要制作iPhone配套应用程序。 因此,我开始了使用Xcode和界面生成器创建应用程序的有趣任务。 Watch应用的情节提要很棒。 堆栈面板的工作方式很棒,您可以覆盖控件,甚至在视图下添加SpriteKit / SceneKit场景-这使您可以创建一些出色的布局,以简单直观的方式完成出色的工作。 iPhone版本稍微复杂一些。 我无法将SpriteKit和标准视图混合使用,因此不得不依靠Core Animation来创建我以前在SpriteKit中完成的效果。 因此,我无法从制作游戏中获得的知识无法得到应用,这意味着我不得不花时间学习新系统。 我还发现创建响应式视图比在WatchKit中复杂得多,并且在一些简单的事情上苦苦挣扎,例如使堆栈视图内容保持固定大小。 我最终会遇到一堆束缚,必须删除并重新开始。 幸运的是,RayWenderlich.com发布了他们的培训视频的Udemy版本,其中包括涉及我所苦苦挣扎的部分的部分,例如堆栈视图以及如何将键盘与滚动视图一起使用。 我对iPhone应用程序所做的一件事是使用矢量图像而不是png。 它们的效果非常好,所以我回过头来更新了Watch,使其也使用矢量。 原始的iPhone应用程序具有浅色主题设计。 我要求在社交媒体上提供一些反馈,并获得了很好的建议。 […]

AR你为未来做好准备吗? 第1部分:iOS上的ARKit入门

苹果公司的ARKit不断发展,使开发人员能够比以往更深入地吸引用户。 通过吉尔·斯科特(Jill Scott) 随着各行各业的公司寻求与受众互动的新方式,productOps的我们正在使用增强现实技术,将移动应用程序从信息内容提升为体验内容。 借助ARKit,Apple提供了强大的SDK,可为iPhone构建AR体验。 它允许开发人员使用iPhone相机在3D空间中放置和操纵对象。 该博客快速浏览了ARKit,其引人入胜的功能,令人印象深刻的视觉效果以及广泛适用的工具包。 随着ARKit 2的发布,开发人员可以使用更多功能,包括持久性体验,共享体验,对象检测和跟踪。 我制作了一个快速而肮脏的Pokemon Go样机,以演示将交互功能实现到移动设备中的简便性。 熟悉Swift会有所帮助,但无需任何经验即可继续学习! 什么是AR和ARKit? AR对开发人员意味着什么? 让我们从Wikipedia定义开始: 增强现实 ( AR )是在现实世界环境中的互动体验,其中驻留在现实世界中的对象被计算机生成的感知信息“增强”。 您可能已经熟悉了流行的AR应用程序Pokemon Go! 您举起手机的摄像头,可以在屏幕上看到周围的环境,但是添加了一点点小动物就可以“捕捉”。 稍后,我们将返回此示例,作为我们的AR教程的基础。 AR可以分为两种类型的体验: 建设性和破坏性 。 前者为环境添加了元素,而后者则将其带走。 作为一个基本示例,想象一个室内设计应用程序。 富有建设性的AR体验将使您看到您的空间中新沙发的外观,而破坏性的体验将使您看到没有旧的大学craiglist沙发的空间。 我们为什么要关心移动AR? 重点是什么? 为什么要为移动用户集成AR体验? 吸引人。 它以许多其他应用程序功能无法实现的方式集成到用户的生活中。 用户在一个新的层次上与产品或想法进行交互,并查看其如何适应他们周围的世界。 它是先进的。 尽管集成起来相对简单,但结果在技术上令人瞩目。 有帮助 请参阅《汤姆指南》的这篇文章,以了解如何使用AR来创建从学习语言到探索博物馆再到选择化妆的真正有用的工具。 我们的应用 对于一个教程,我们将创建我亲切地称为“ Janky Pokemon”的东西。 这是Pokemon Go类应用的快速又肮脏的娱乐。 它不会支持应用程序商店,但是它将演示建立基本的AR体验是多么简单。 我们将从小处着手。 让我们设置项目并在屏幕上显示一个对象。 项目设置:第一步 首先创建一个情节提要,然后将一个AR场景视图添加到视图控制器中: 现在创建一个新的视图控制器,添加导入,遵循ARKit委托协议,并创建一个连接到场景视图的IBOutlet: 在viewDidLoad中设置场景视图并在viewWillAppear中运行它: 如果我们离开视图,我们想暂停会话: 现在让我们创建一个函数来向环境添加一个简单的盒子: 现在,只需在viewDidLoad中调用该函数并运行即可。 […]

在Swift 3.0及更高版本中上传到服务器之前,图像方向是否正确?

您可以从应用中拍摄一张照片,然后将其以纵向显示在图像视图中,但是每当将此图像上载到服务器时,该图像的原始方向都没有。 因此,来自服务器的图像将原始人像图像旋转90度。 因此,您必须正确旋转,然后才能在服务器上上传原始图像。 在此处创建功能,以便在Swift 3.0及更高版本中定位图像。 func imageOrientation(_ srcImage:UIImage)-> UIImage { 如果srcImage.imageOrientation == UIImageOrientation.up { 返回srcImage } var转换:CGAffineTransform = CGAffineTransform.identity 切换srcImage.imageOrientation { case UIImageOrientation.down,UIImageOrientation.downMirrored: transform = transform.translatedBy(x:srcImage.size.width,y:srcImage.size.height) 转换= transform.rotated(作者:CGFloat(M_PI))//使用Swift 4.0时用Double.pi替换M_PI 打破 case UIImageOrientation.left,UIImageOrientation.leftMirrored: transform = transform.translatedBy(x:srcImage.size.width,y:0) 当使用Swift 4.0时,transform = transform.rotated(作者:CGFloat(M_PI_2))//用Double.pi / 2替换M_PI_2 打破 case UIImageOrientation.right,UIImageOrientation.rightMirrored: transform = transform.translatedBy(x:0,y:srcImage.size.height) 当使用Swift 4.0时,transform = transform.rotated(作者:CGFloat(-M_PI_2))//用Double.pi / 2替换M_PI_2 打破 案例UIImageOrientation.up,UIImageOrientation.upMirrored: […]

在Swift中展开和编辑iOS表格单元格

来自 petethedeveloper.com的交叉发布 最近,我们实现了一项功能,该功能允许用户向UITextView中输入任意数量的文本,而UITextView本身包含在UITableViewCell中。 要求如下: textview不可滚动。 而是,textview应该随着内容大小的增加/减小而扩展/折叠。 textview永远不会小于指定的基本大小 单元格应该因为包含的textview展开/折叠而展开/折叠 下面,我描述我们如何做到的。 实施 实现分为三个步骤: 当textview的内容更改时,计算显示所有内容所需的框架的大小。 这是使用以下方法在UITextViewDelegate textViewDidChange(textView :)方法中计算的; / *计算显示所包含内容所需的帧大小 内容* / 让fixedWidth = textView.frame.size.width 让newSize = textView.sizeThatFits(CGSize(width:fixedWidth,height:.greatestFiniteMagnitude)) var newFrame = textView.frame 如果显示文本所需的框架大小与当前的textview框架大小不同,请更新textview框架的大小。 请记住,我们绝不会将textview框架的大小更新为小于我们指定的基本框架大小; //我们的基本身高 let baseHeight:CGFloat = 50 / *我们的新高度绝对不能小于我们的基本高度,因此请使用两个中的较大者* / 让高度:CGFloat = newSize.height> baseHeight? newSize.height:baseHeight newFrame.size = CGSize(width:max(newSize.width,fixedWidth),height:height) 当textview的框架大小更改时,更新out表单元格的大小以匹配所包含textview大小的大小。 我们使用委托协议来告诉UITableViewController更新单元格高度。 我们传递计算出的框架高度,然后将其作为单元格的高度返回给UITableViewDelegate tableView(:heightForRowAt :)方法; //保存新高度 EditorialCellHeight = […]

状态栏在iOS 9+中发脾气

如果您的应用支持iOS 9+ ,则您已使用修改了状态栏样式。 UIApplication.shared.setStatusBarStyle( .lightContent, 动画:真实 ) ..那么您一定已经看到上面的警告说它已经过时了! 与往常一样,它也建议我们使用替代的新方法。 覆盖var preferredStatusBarStyle:UIStatusBarStyle { 返回.lightContent } 如果您还没有使用过它,那么就让我们来谈谈吧,您可以跳到下一部分,我在这里讨论了在某些情况下它如何发脾气😒 preferredStatusBarStyle是UIViewController上的新UIViewController 。 必须在自定义视图控制器中覆盖它,这意味着在这里您可以控制其状态栏(黑色或白色👍)的样式。 每当加载控制器时,都会调用此属性。 在某些情况下,您的控制器可能希望根据某些条件(例如您滚动了多少)来再次更新其状态栏样式。 在这种情况下,您可以致电.. setNeedsStatusBarAppearanceUpdate() 此方法强制iOS更新其状态栏,并且在此过程中它将调用preferredStatusBarStyle 再次👍。 因此,您也可以根据需要强制iOS更新其状态栏😊 一切看起来不错吧? 😈 在一种情况下,这是行不通的,即您的控制器已嵌入导航堆栈中。 原因是iOS需要父控制器 (而不是子控制器) 决定需要显示哪种状态栏! 让我们看看在这种情况下会发生什么。 子控制器的preferredStatusBarStyle 不会被调用 其父导航控制器的 preferredStatusBarStyle 将被调用 现在不用担心,您不必UINavigationController子类来处理状态栏更新。 相反,我们可以利用扩展来进行救援。 您只需在代码库中添加以下逻辑即可。 扩展UINavigationController { 打开覆盖var preferredStatusBarStyle:UIStatusBarStyle { 返回topViewController?.preferredStatusBarStyle? 。默认 } } ..此逻辑仅表示您正在要求导航堆栈的topViewController决定需要显示哪种状态栏,以显示topViewController除了屏幕上当前的控制器topViewController什么都没有! 这样,您仍然可以在当前控制器中处理更新🚀 不确定为什么苹果决定这样做,但我们必须应对它