Singletons模式提供了对象的全局可访问共享实例。 在大多数情况下,您在iOS中不需要单例(这可能会被滥用以形成结构不良的代码),但是在某些情况下,仅拥有一个类的实例是有意义的。 。 苹果公司经常使用这种方法。 例如:UIApplication.sharedApplication(),NSUserDefaults.standardUserDefaults(),NSFileManager.defaultManager()均返回Singleton对象。 在Objective-C中 ,为确保仅创建一个单例对象的实例,将其初始化包装在调用dispatch_once函数中,该函数在应用程序的生命周期内一次执行一次块。 在Swift中 ,使用静态类型属性只是必要的,即使同时访问多个线程,该属性也只能被延迟初始化一次: 就是…单线单人! 用法是: Singleton.sharedInstance 由于所有对象都在Swift中带有默认的公共初始化程序,因此我们需要覆盖init并将其设为private 。 这样可以确保单例确实是唯一的,并防止外部对象创建自己的此类实例。 Singleton Shoudl也是最终版本,以防止将其子类化(如果Singleton需要其他功能,则应将其封装在扩展中)。 因此,我们需要添加另一行: 这是Singleton的最终正确实现。 感谢Michael Ormonde提出的“私有初始化”建议。 希望本文对您有所帮助。 谢谢阅读!
在编程中,通常有很多不同的方法可以达到相同的目的。 我在上一篇文章(“功能性” Swift#6:视图样式)中提出了一些想法。 以下是解决同一问题(设计视图样式)的其他10种变化。 有些只是其他的小变体,这是为了演示Swift语言功能或模式。 在本文中,我将不加评论或推荐地介绍这些内容。 它们都是实现相同结果的有效方法,每种方法都有其位置。 逐行 让myBtn = UIButton() myBtn.backgroundColor = .red myBtn.frame = CGRect(x:10,y:10,宽度:30,高度:30) myBtn.isUserInteractionEnabled = true 2.子类(和变体-通过参数/样式方法/ layoutSubviews覆盖样式等传递样式) 类MyButton:UIButton { 覆盖init() { super.init() self.backgroundColor = .red self.frame = CGRect(x:10,y:10,宽度:30,高度:30) self.isUserInteractionEnabled = true } } 让myBtn = MyButton() 3.使用(例如:使用然后) 让myBtn = UIButton()。with { $ 0.backgroundColor = .red $ 0.frame = CGRect(x:10,y:10,宽度:30,高度:30) $ […]
Objective-C仍然值得花时间吗? 目前,我只能说swift与Objective-C一起工作, 在我们的应用程序的核心,我们仍然有它的线索。 基础 在Objective-C中,我们有两种文件类型: 头文件和实现文件。 在头文件中,我们将解释在编码结束时应该具有的内容,我们不必将实现文件实现到另一个实现文件中,只需添加头文件,然后完成即可。 在开始编写代码之前,我将从编码的重要部分开始,您应该能够在一个大团队中解释您的代码,因此,这是Objective-C中的一些文档规则 / *! @brief它将温度度从华氏度转换为摄氏度。 @discussion该方法接受一个表示温度的浮点值,该值以华氏度表示,并将其转换为摄氏温度刻度。要使用它,只需调用@c [self toCelsius:50 ]; @param fromFahrenheit输入值,代表华氏度的度数。 @码 float f = [self toCelsius:80]; @return float摄氏度的度数。 * /
在几乎每个应用程序中,都有一段时间我们必须进行一些格式化。 有时我们需要将Bool转换为可读的字符串,更经常的是将Date对象转换为文本文字,这对于使用我们的应用程序的人来说是可以理解的,而不是说用逗号/点号将数字四舍五入到两个空格(取决于国家/地区或操作系统设置)或在数字的千分之一之间放置分隔符。 Apple满足了这一要求,并创建了可在我们的应用程序中使用的格式化程序集。 苹果开发人员的意图是创建非常清晰的API,该API将是独立于国家/地区的,而且也非常可定制。 他们为此做得很好。 例如,要创建DateFormatter以在屏幕上的单个标签中打印不带时间的Date ,我们必须: var date:Date = // … 2001-01-02 func setupDate(){ 让dateFormatter = DateFormatter() dateFormatter.dateStyle = .mediumStyle dateFormatter.timeStyle = .noStyle dateLabel.text = dateFormatter.string(来自:日期) } 这将根据iOS或OS X语言首选项显示不同的字符串。 如果我们使用英语作为默认语言,它将显示Jan 2, 2001,对于法语,我们将显示2 janv. 2001 2 janv. 2001 ,对于日语,我们得到2001/01/02 。 其余的格式化程序具有非常相似的API。 我们可以使用枚举根据语言偏好来定义行为,但是我们也可以使用字符串格式来创建独立于系统配置的格式化程序。 当我们将日期作为字符串发送到REST服务时,我们可以将格式器定义为: func getCurrentDateStringForRest()->字符串{ 让dateFormatter = DateFormatter() dateFormatter.dateFormat =“ yyyy-MM-dd HH:mm:ss” 返回dateFormatter.string(来自:Date()) }
您是否曾经遇到过这样的情况,即您的viewController变得如此紧密并相互依赖。 您的导航分散在您的所有代码中。 您可能还听说过Massive视图控制器问题。 这与以下事实有关:MVC模式的视图控制器通常会做过多的工作,包括视图设置代码本身。 以某种方式使视图控制器实际上变成一个视图(还有更多…) 视图控制器不应该执行的任务之一。 屏幕导航管理和应用程序流程。 什么是协调器模式? 由Soroush Khanlou在2015年NSSpain会议上介绍给iOS社区。Coordinator模式提供了导航逻辑的封装。 换句话说:而不是从其他视图控制器推送和呈现ViewController。 所有屏幕导航将由协调员管理。 因此,视图控制器将被隔离并且彼此不可见 ,并且可以轻松地重用 。 如上图所示。 协调器模式可以通过以下方式描述: 我们可能有一个协调员一个或多个视图控制器。 每个协调器都使用通常称为“ start ”的方法显示其viewController。 每个viewController都有一个对其协调器的委托引用。 每个协调员都有一系列子协调员。 每个子协调器都有对其父级的委托引用。 让我们继续练习。 重要提示:您可能会发现以下示例与其他实现略有不同。 这就是我个人使用它的方式。 但是主要机制在任何地方都是相同的。 在这里,我们将有两个协调器管理三个视图控制器,以表明一个协调器可以具有一个或多个视图。 快速创建一个新的单视图项目。 具有三个视图控制器:FirstViewController,SecondViewController和ThirdViewController。 在每个视图控制器上,添加一个按钮以导航到以下视图控制器。 首先,我们将创建一个协调器协议。 通过一个子协调器数组和一个初始化方法,该方法接收导航控制器作为参数。 然后是第一个协调器,它将管理第一个视图控制器。 使用start方法实现,将第一个视图控制器添加到导航控制器中。 firstCoordinator有两个扩展,一个用于导航到下一个viewController。 第二个是导航回第一个协调器。 我们需要保持子协调器数组与当前协调器堆栈更新。 然后,不要直接在didfinishlaunchingwithoptions方法中创建主控制器。 我们使用主navigationController作为参数创建了第一个协调器。 并且start方法将负责显示第一个viewController。 现在为了导航到下一个viewController。 我们将不得不致电协调员。 由FirstViewControllerDelegate表示。 正如先前所说。 协调者可以管理一个或多个viewController。 因此,在这里,secondCoordinator将同时处理第二个和第三个viewControllers。 首先,我们创建一个自定义的后退按钮,调用一个协调器方法navigationToFirstpage : 重要说明 :在协调器之间切换时。 如果未覆盖操作,则默认的导航控制器后退按钮将中断协调器逻辑 。 我们应该绝对使用协调器方法调用自己的后退操作,以确保子协调器数组得到正确更新 […]
如果您想找到架构风格的新东西,而您对MVC和MVVM则不感兴趣。 现在该检查VIPER了。 也许这是您的下一代项目。 关于它的优缺点,有很多材料。 以下链接: 自强/ VIPER书 VIPER书–唯一的 github.com 良好的iOS应用程序体系结构:MVVM与MVC与VIPER MVVM,MVC,VIPER…这么多缩写,哪种架构是最好的? 让我们来谈一谈永远重要的事情…… 学术领域 使用VIPER构建iOS应用程序·objc.io objc.io出版有关iOS和OS X开发的高级技术和实践的书籍 www.objc.io 反馈 如果您想区分班级之间的责任,VIPER有助于变得更加灵活。 不同的层可帮助您轻松完成任务,而不会破坏以前的实现。 这是SOLID的一种单一责任原则。 如果我们谈论缺点:如果项目应该像原型,那么架构将不是最好的,因为它具有大量的类和其他代码。 但是,如果您要从原型移出项目,则可能是其中一种方法。 建议 尝试在宠物或测试项目中使用VIPER。 在那里,您可以接触到所有方面,并且稍后在理解主项目中的使用原理之后。 例如,您可以检查我的测试项目,其中包含对任务的不同要求: sergVn / VIPER体系结构示例 通过在GitHub上创建一个帐户来为VIPER-architecture-example开发做出贡献。 github.com 新的VIPER竞赛正在等着您,检查自己😉
优秀开发人员的特性之一是预测项目中的更改并编写准备好应对这些更改的代码。 每个开发人员都知道依赖项注入和组合模式。 但是程序员经常不使用这些工具。 我的意思是,您经常会看到与网络一起使用的职责是一个单独的类,而另一个类则与数据库一起使用。 但是,较小的职责不会在单独的类中承担,而是属于某个模块的逻辑。 我认为这是不正确的,我将尝试解释如何进行更改。 如果您的困难模块看起来像是大正方形除以较小的正方形,那真的很好。 让我们尝试编写一些代码,然后以良好的方式对其进行重构。 我们的程序将包含一个图像和一个按钮,单击按钮后,该图像将带有alpha效果。 让我们编写代码。 首先,我们创建这个viewcontroller。 代码很简单,一切都很好。 现在,我想告诉您为什么此代码带有异味。 正如我之前所写的,将代码分成小块很重要,无论它是具有困难逻辑的大型服务还是仅用于呈现图像的助手。 在单独的类中,您需要分配所有单独的逻辑。 这是一个很好的例子,在单独的课程中,您可以处理图像。 下一步是重构。 🙂 最后一步是工厂。 这些控制器至少有两个配置。 Factory可以帮助您以一种更简单的方式生成新的控制器,并且通过这种模式,您可以随时为所有控制器装配零件。 有两种类型的图像渲染助手的工厂 上面,我试图向您展示,如果您在单独的类中组成甚至很小的逻辑块,也会更好。 我希望它是有趣和有用的。 如果您在代码中使用我的建议,那将是我的荣幸。