swift入门_属性的那些坑

作者: 明月钓无痕 | 来源:发表于2016-02-22 11:54 被阅读1523次

    说起swift的第一个难点,就是关于属性.对于刚开始接触OC时实例变量/成员变量/属性,傻傻分不清.自从接触到了Swift,才知道那都不是事儿.
    下面就来看看Swift的属性是怎么回事.
    属性又分为存储属性,计算属性,类属性

    1.存储属性

    对于存储属性,没有什么好说的.对于熟悉OC的来说是一样的.

    // 定义一个类
    class Person {
      // 下面的定义的都是属性,而且是存储属性,和OC相同,为了保存属性值
      // 使用var 定义可变属性变量
        var age: Int = 10
      // 使用let 定义不可变的属性常量
        let name: String = "张三"
      // 使用? 表示这个是可选值
     // 上面两个变量必须有初始值,所以在定义变量时进行了赋值
     // height变量由于是可选的,没有必要赋初值
        var height: Double?
    }
    // 这里定义了一个Person对象
    let p = Person()
    // 由于age,height都是变量,可以直接通过点语法进项属性赋值
    p.age = 5 
    p.height = 200
    //p.name = "李四" // 由于name是定义的是常量,这里赋值是报错的
    

    2.计算属性

    刚才提到的存储属性还是觉得很正常的,但是用习惯了OC,对于习惯了set和get方法的人们来说,刚开始简直是噩梦.这玩意是什么鬼.
    下面拿来我之前写过的一个分类来说明一下.
    有时候我们为了设置frame的x,y,w,h我们需要一层层点下去,这里写一个分类,为了方便赋值取值.我们直接为View加了个属性.这样子我们通过set和get进行赋值和取值.这个应该很熟悉了

    @property (nonatomic, assign) CGFloat x;
    @property (nonatomic, assign) CGFloat y;
    @property (nonatomic, assign) CGFloat width;
    @property (nonatomic, assign) CGFloat height;
    
    // x
    - (void)setX:(CGFloat)x {
        CGRect frame = self.frame;
        frame.origin.x = x;
        self.frame = frame;
    }
    
    - (CGFloat)x {
        return self.frame.origin.x;
    }
    
    //...写法类似,只去了个
    

    那个类似的功能我们使用swift来看一下,对UIView写了一个扩展.

    extension UIView {
        var x: CGFloat {
        // get方法
        // 需要注意的是:写了set,get是必须写的,如果只写get,相当于只读.
            get {
               return self.frame.origin.x
            }
            // set 方法
            set {
                var frame = self.frame
                frame.origin.x = newValue
                self.frame = frame
            }
        }
    }
    

    看到Swift的代码,可能会很吃惊,这不是很像吗?对是相同的代码.写法是相同的.但是实际上和OC还是有很大区别的.
    注意
    1.计算属性的值是不固定的,是计算得来的,所以只能使用var来修饰,不能使用let
    2.计算属性本身是不能直接复制的,他是通过其他的变/常量计算结果得到的数据.

    // 由于Swift我们没有成员变量,所以我们要避免死循环的问题
    // 所以再OC中常用到的_xxx,在Swift中不好用了
    
    class Person {
    // 下面由于进行了赋值,其实是一个存储属性,再去写get方法是没意义的.
    //    var age: Int = 10 {
    //        return 20
    //    }
        
      // 这种情况都会是死循环,具体是什么原因,熟悉OC的应该没问题吧
        var age: Int {
            get {
                return age
            }
            
            set {
                age = newValue
            }
        }
    }
    

    说道这里我们就得提一下懒加载,在OC中我们的懒加载其实是重写了属性的get方法,在Swift中就要改变一下写法了

    // 定义了一个属性
    @property (nonatomic, strong) NSMutableArray *topics;
    
    // 懒加载
    - (NSMutableArray *)topics
    {
        if (!_topics) {
            _topics = [NSMutableArray array];
        }
        return _topics;
    }
    

    Swift中的懒加载会使用到关键字lazy

    lazy var topics: NSMutableArray? = NSMutableArray()
    
    // 当然如果要在懒加载时做一下初始化配置,那么我们会使用闭包的形式
    lazy var topics: NSMutableArray? = {
        // 这里面进行初始化配置
    }()
    
     // 懒加载 ps: 这是从项目中截取的一段,为了说明问题,直接拷贝会报错
        lazy var pictureView: DZTopicPictureView? = {
            let pictureView = DZTopicPictureView.pictureView()
            self.contentView.addSubview(pictureView)
            return pictureView 
        }()
    

    通过这里我们似乎觉的get/set和OC中有了区别了,那么再看看下面一个

    3.属性监视器

    所谓的属性监视器,就是在属性值的改变前后进行一些操作,这个才是相当于我们的OC中所说的get方法,拿到值后再进行一些操作

    class Person {
        var age: Int?  {
            willSet {
                print(newValue) // newValue将要新赋的值5
            }
      // 当然如果觉得不习惯使用newValue/oldValue, 我们可以取一个内部变量名,didSet也是可以的
     //  willSet(age) {
     //           print(age)            
      //      }
            didSet {
                print(oldValue) // oldValue表示旧值 nil
            }
        }    
    }
    
    let p = Person()
    p.age = 5
    
    

    注意
    1.计算属性有get和set方法去改变属性值,因此监听就就没什么意义了
    2.设置默认值时不会调用willSet和didSet,见下面代码.

    class Person {
      // 默认值
        var age: Int? = 20  {
            willSet {
                print(newValue) 
            }
            didSet {
                print(oldValue)
            }
        }    
    }
    

    3.willSet和didSet set和get 是不能共存的.

    所以说在定义属性前还是要想好属性是做什么用的

    相关文章

      网友评论

        本文标题:swift入门_属性的那些坑

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