要给类添加属性,一种是直接添加到struct _LyFile {GObject parent;}里,但一定要保证这个parent是在第一的位置上。
gobject还提供了另一种给类添加属性的方式,顺便给类加一个方法进去,先看头文件,新增了一个构造函数和一个类方法,新增的类方法跟这次讲的属性有关联

接下来是c文件,c文件增了很多样板代码,一点点往下看

先是在struct _LyFile里增加了一个id的属性,还声明定义了一个LyFilePrivate的结构体,将定义类的方式由G_DEFINE_TYPE改为了G_DEFINE_TYPE_WITH_PRIVATE.新增加的这个结构体就是用来存放类属性的,命名方式为完整类名+Private。

后面一部分的内容:
1. 定义了一个匿名枚举,开头一个PROP_0是用来占位,最后一个是用来说明这个类对外提供了多少个属性,注意是对外,也就是你可以在LyFilePrivate定义很多个属性,但你只提供一部分属性供外部get/set,剩下的则是内部使用,枚举名字任意,能清楚表达意思就行;
2. 定义了一个FILE_PROPERTY的静态变量,这个变量主要用来存储对外提供的属性的相关信息,如属性的类型、字符串名、默认值等, 注意一定要将首元素设置为NULL,第一个是保留给gobject内部使用的,这也是为什么上面需要一个PROP_0来占位的原因。
3. 之后定义了get/set两个函数,具体的内容之后在看;
4. 在class_init()中将定义好的get/set函数赋值给GObjectClass,这里的原因是gobject提供多种方式来获取或设置这些属性,那么就需要设置恰当的规则来引导gobject正确行动。目前还没有提供gobject这些属性的各种信息,接下来就是了,给上面的定义的静态变量初始化相应的元素,用到的就是g_param_spec_xxxx()这类函数,如果是属性是int类型,则使用g_param_spec_int()来初始化,第一个参数是这个属性的字符串名字,第二和第三个参数我一般都是NULL(这俩我也不太懂,nick好像是别名的意思),之后的参数不同类型也不同的解释,数值类的一般是最小值、最大值、默认值,字符串则只有一个默认值了,最后一个是属性的标志,主要用来说明这个属性的是否可读可写,是否仅在构造对象的时候初始化,是否允许发出通知(这个涉及到更后面的内容——信号)等。然后将这些属性信息提供给gobject,也就是最后一步g_object_class_install_properties()
现在回过头来看看get/set函数的实现,参数必须跟图片上的保持一致,

这部分的内容很简单:
gobject在生成对象时,自动生成一个LyFilePrivate变量,并分配相应的存储空间,G_DEFINE_TYPE_WITH_PRIVATE()给我们提供了如何访这个变量的方法,ly_file_get_instance_private(),也就是类方法前缀ly_file+get_instance_private()形式,注意这个方法的参数是LyFile对象,但get/set函数提供的参数是GObject对象,所以需要进行类型转换,不建议使用强制转换,而是使用相应的宏LY_FILE(),这个宏还会在运行时做检查,如果不能正确转换则会产生错误信息并打印在控制台,但不会退出程序。之后就是利用先前定义好的匿名枚举来筛选想要对哪个属性进行操作,get属性则将属性的设置给value,set属性则从value取出值再赋值给相应的属性,这里name属性由于是字符串,在设置时使用g_strdup(等同于strdup),会分配额外的内存,在重新设置之前需要释放掉原先的资源。

接下来看看在头文件中新增的两个函数的实现,
1. 新的构造函数,带有一个uid的参数,依然使用g_object_new()来生成,最后多了一个“uid”和uid的值,这就是给属性赋初值,并且这个是成对出现,"uid"则是这个属性的字符串名字,uid则是将要赋的初值,当然最后的NULL别忘了加上,如果还要加上name,使用g_object_new(LY_TYPE_FILE, "uid", uid, "name", "LuoYi", NULL);
2. 新增的类方法,上面的讲过了,再提个醒,类方法的第一个参数一般都是LyFile *self
等等这就完了?上面那个name分配的内存只在重新设置的时候释放,然后又申请了新的内存,当这个对象使用完,name分配的内存什么时候释放呢,gobject又不知道我们申请了这块内存啊。这里有两种方式来实现

一个使用dispose,一个使用finalize,这俩都是用来清理的,但只有finalize算是析构函数,根据官方的解释当对象使用完之后,finalize只会调用一次,并且再dispose之后,而dispose可能会被多次调用,使用dispose时就需要做校验了,不然可能会出多次释放同一块内存了,最后再加上调用父类的同名函数,来释放父类的占用的资源,我的习惯是只finalize。最后别忘了在class_init()中,将相应函数赋值给gobjectclass哦。
明天周六了还要上班,然后休息,休息,休息。周一晚上休息之前再尝试更新一下吧