美文网首页swift
Swift基础5(结构体和类)

Swift基础5(结构体和类)

作者: SunshineBrother | 来源:发表于2019-11-18 11:53 被阅读0次

    类与结构体的对比

    在 Swift 中类和结构体有很多共同之处

    • 定义属性用来存储值;
    • 定义方法用于提供功能;
    • 定义下标脚本用来允许使用下标语法访问值;
    • 定义初始化器用于初始化状态;
    • 可以被扩展来默认所没有的功能;
    • 遵循协议来针对特定类型提供标准功能。

    类有而结构体没有的额外功能

    • 继承允许一个类继承另一个类的特征;
    • 类型转换允许你在运行检查和解释一个类实例的类型;
    • 反初始化器允许一个类实例释放任何其所被分配的资源;
    • 引用计数允许不止一个对类实例的引用。

    结构体

    在swift标准库中,绝大多数的类型都是结构体,而枚举和类只占一小部分。比如Bool、Int、Double、String、Array、Dictionary等常见的类型都是结构体

    结构体初始化器

    编译器会根据情况,可能会为结构体生成多个初始化器,宗旨:保证所有的成员都有值

    结构体初始化器.png

    所有结构体都有一个编译器自动生成的初始化器

    思考:下面的代码能够通过编译器吗

    struct Point {
        var x:Int?
        var y:Int?
    }
    var p1 = Point(x: 1, y: 2)
    var p2 = Point(x: 1)
    var p3 = Point()
    

    答案是可以的

    可选项都有一个默认值nil

    自定义初始化器

    一旦在自定义结构体时自定义了初始化器,编译器就不会再帮它自动生成其他初始化器了

    在没有自定义初始化器的时候,下面三种情况都是可以通过编译的

    struct Point {
        var x:Int = 0
        var y:Int = 1
    }
    var p1 = Point(x: 1, y: 2)
    var p2 = Point(x: 1)
    var p3 = Point()
    

    而自定义了初始化器

    struct Point {
        var x:Int = 0
        var y:Int = 1
        init(x:Int,y:Int) {
            self.x = x
            self.y = y
        }
    }
    var p1 = Point(x: 1, y: 2)
    var p2 = Point(x: 1)
    var p3 = Point()
    
    自定义初始化器.png

    类的定义和结构体相似,但是编译器并没有为类自动生成可以传入成员值的初始化器

    类和结构体的本质区别

    • 结构体和枚举是值类型:值类型是一种当它被指定到常量或者变量,或者被传递给函数时会被拷贝的类型。
    • 类是引用类型:不同于值类型,在引用类型被赋值到一个常量,变量或者本身被传递到一个函数的时候它是不会被拷贝的。相对于拷贝,这里使用的是同一个对现存实例的引用。

    用结构体和元组构建更整洁的类

    转载:用结构体和元组构建更整洁的类

    假设你正在开发一款社交网络应用,其中包含了一个带有关注按钮和点赞按钮的用户图片展示组件。同时,为了满足单一功能原则(single responsibility principle)和视图控制器的构成,点赞和关注的实现应该另有它处。社交网络不仅有高级账户,也有企业账户,因此 InteractiveUserImageController(命名从来不是我的强项) 要能满足一系列的配置选项。以下是这个类一个可能的实现(为作展示,示例代码保留了不少可改进的地方):

    final class InteractiveUserImageController: UIView {
        /// 是否需要展示高级布局
        var isPremium: Bool
        /// 账户类型
        var accountType: AccountType
        /// 点击视图是否高亮
        var isHighlighted: Bool
        /// 用户名
        var username: String
        /// 用户头像
        var profileImage: UIImage
        /// 当前用户是否能点赞该用户
        var canLike: Bool
        /// 当前用户是否能关注该用户
        var canFollow: Bool
        /// 大赞按钮是否能使用
        var bigLikeButton: Bool
        /// 针对一些内容使用特殊的背景色
        var alternativeBackgroundColor: Bool
    
        init(...) {}
    }
    

    至此,我们就有了不少参数。随着应用体量的增长,会有更多的参数被加进类里。将这些参数通过职能进行划分和重构固然可行,但有时保持了单一功能后仍会有大量的参数存在。要如何才能更好的组织代码呢?

    Swift 结构体结构

    Swift 的struct类型在这种情况能发挥巨大的作用。依据参数的类型将它们装进一次性结构体:

    final class InteractiveUserImageController: UIView {
        struct DisplayOptions {
            /// 大赞按钮是否能使用
            var bigLikeButton: Bool
            /// 针对一些内容使用特殊的背景色
            var alternativeBackgroundColor: Bool
            /// 是否需要展示高级布局
            var isPremium: Bool
        }
        struct UserOptions {
            /// 账户类型
            var accountType: AccountType
            /// 用户名
            var username: String
            /// 用户头像
            var profileImage: UIImage
        }
        struct State {
            /// 点击视图是否高亮
            var isHighlighted: Bool
            /// 当前用户是否能点赞该用户
            var canLike: Bool
            /// 当前用户是否能关注该用户
            var canFollow: Bool
        }
    
        var displayOptions = DisplayOptions(...)
        var userOptions = UserOptions(...)
        var state = State(...)
    
        init(...) {}
    }
    

    正如你所见,我们把这些状态放入了独立的 struct 类型中。不仅让类更整洁,也便于新上手的开发者找到相关联的选项。
    已经是一个不错的改进了,但我们能做得更好!
    我们面临的问题是查找一个参数需要额外的操作。
    由于使用了一次性结构体类型,我们需要在某处定义它们(例如:struct DisplayOptions),也需要将它们实例化(例如:let displayOptions = DisplayOptions(...))。大体上来说没什么问题,但在更大的类中,为确定 displayOptions 的类型仍旧需要一次额外的查询。然而,与 C 语言不同,像下面这样的匿名struct在 Swift 里并不存在:

    let displayOptions = struct {
        /// 大赞按钮是否能使用
        var bigLikeButton: Bool
        /// 针对一些内容使用特殊的背景色
        var alternativeBackgroundColor: Bool
        /// 是否需要展示高级布局
        var isPremium: Bool
    }
    

    元组 – 匿名结构体在 Swift 中的实现

    实际上,Swift 中还真有这么一个类型。它就是我们的老朋友,tuple。自己看吧:

    var displayOptions: (
      bigLikeButton: Bool,
      alternativeBackgroundColor: Bool,
      isPremium: Bool
    )
    

    这里定义了一个新的类型 displayOptions,带有三个参数(bigLikeButton,alternativeBackgroundColor,isPremium),它能像前面的 struct 一样被访问:
    user.displayOptions.alternativeBackgroundColor = true
    更好的是,参数定义不需要做额外的初始化,一切都井然有序。

    强制不可变性

    最后,tuple 既可以是 可变的 也可以是 不可变的。正如你在第一行所看到的那样:我们定义的是var displayOptions而不是 varlet bigLikeButton。bigLikeButtondisplayOptions一样也是var`。这样做的好处在于强制把静态常量(例如行高,头部高度)放入一个不同的(let)组。

    添加数据

    当需要用一些值初始化参数时,你也能很好的利用这个特性,这是一个加分项:

    var displayOptions = (
      bigLikeButton: true,
      alternativeBackgroundColor: false,
      isPremium: false,
      defaultUsername: "Anonymous"
    )
    

    简化

    相比于使用结构体而言,使用了元组的选项集能更轻易的简化代码:

    class UserFollowComponent {
        var displayOptions = (
            likeButton: (
                bigButton: true,
                alternativeBackgroundColor: true
                ),
            imageView: (
                highlightLineWidth: 2.0,
                defaultColor: "#33854"
            )
        )
    }
    

    相关文章

      网友评论

        本文标题:Swift基础5(结构体和类)

        本文链接:https://www.haomeiwen.com/subject/mhivictx.html