asp网站设计代做,狼雨的seo教程,网站网页设计怎样,成都网站建设哪里有The GObject base class
Object memory management
Gobject的内存管理相关的API很复杂#xff0c;但其目标是提供一个基于引用计数的灵活的内存管理模式。
下面我们来介绍一下#xff0c;与管理引用计数相关的函数。
Reference Count
函数g_object_ref和g_object_unref的…The GObject base class
Object memory management
Gobject的内存管理相关的API很复杂但其目标是提供一个基于引用计数的灵活的内存管理模式。
下面我们来介绍一下与管理引用计数相关的函数。
Reference Count
函数g_object_ref和g_object_unref的作用分别是增加和减少引用计数。g_clear_object函数是对g_object_unref的封装。
在调用g_object_new时引用计数是1,1代表到目前为止使用此函数的使用者是此对象的唯一使用者当引用计数是0时对象的类结构体中的disopose()和finalize()会被调用之后会调用g_type_free_instance()来释放对象实例结构体所占用的空间或者返回空间到此类型对象的对象池。如果对象的最后一个实例被释放那么对象的类结构体也会被销毁。
GObject销毁流程如下表 Weak Reference
weak reference 的作用是监视对象的终止(finalization),g_object_weak_ref()会添加一个监视回调函数到对象回调函数不会使对象的引用计数有任何变化它只是在对象运行dispose的时候执行。 Reference counts and cycles
GObject的销毁过程分为两个阶段第一个阶段是在dispose函数中dispose()会释放所有对其它成员对象的引用。第二个阶段是在finalize函数中finalize()会释放对象本身所占用空间。在调用dispose后调用finalize之前对象的方法还能正常执行。
销毁过程分为两个阶段有益于打破循环引用。当检测到循环引用时为了正常进行销毁工作调用g_object_run_dipose就能打破循环。dispose能被多次执行finalize只会执行一次。现在我们举例对这几句话进行说明。假如对象A和对象B相互引用现在我们检测到这样的情况那么现在需要销毁这两个对象该怎么办呢一种方式就是应用程序在操作释放一个对象时调用g_object_run_dispose。
如果对象A全部释放所有对其他引用当然也会释放对对象B的引用。如果这是最后一个对对象B的引用那么A释放对B的引用会导致unref 函数执行对象B的dispose, 进而导致B对象释放对对象A的引用如果这也是对对象A的最后一个引用对象B对对象A的引用的释放会导致第二次执行A的dispose。
Object properties
GObject的一个功能是能够通过set_property/get_property函数对对象属性进行操作。首先我们先举例说明属性如何定义的以及在应用程序中如何使用。
首先看一下定义。
// Implementationtypedef enum
{PROP_FILENAME 1,PROP_ZOOM_LEVEL,N_PROPERTIES
} ViewerFileProperty;static GParamSpec *obj_properties[N_PROPERTIES] { NULL, };static void
viewer_file_set_property (GObject *object,guint property_id,const GValue *value,GParamSpec *pspec)
{ViewerFile *self VIEWER_FILE (object);switch ((ViewerFileProperty) property_id){case PROP_FILENAME:g_free (self-filename);self-filename g_value_dup_string (value);g_print (filename: %s\n, self-filename);break;case PROP_ZOOM_LEVEL:self-zoom_level g_value_get_uint (value);g_print (zoom level: %u\n, self-zoom_level);break;default:/* We dont have any other property... */G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);break;}
}static void
viewer_file_get_property (GObject *object,guint property_id,GValue *value,GParamSpec *pspec)
{ViewerFile *self VIEWER_FILE (object);switch ((ViewerFileProperty) property_id){case PROP_FILENAME:g_value_set_string (value, self-filename);break;case PROP_ZOOM_LEVEL:g_value_set_uint (value, self-zoom_level);break;default:/* We dont have any other property... */G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);break;}
}static void
viewer_file_class_init (ViewerFileClass *klass)
{GObjectClass *object_class G_OBJECT_CLASS (klass);object_class-set_property viewer_file_set_property;object_class-get_property viewer_file_get_property;obj_properties[PROP_FILENAME] g_param_spec_string (filename,Filename,Name of the file to load and display from.,NULL /* default value */,G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);obj_properties[PROP_ZOOM_LEVEL] g_param_spec_uint (zoom-level,Zoom level,Zoom level to view the file at.,0 /* minimum value */,10 /* maximum value */,2 /* default value */,G_PARAM_READWRITE);g_object_class_install_properties (object_class,N_PROPERTIES,obj_properties);
}再看看如何在应用中使用属性。
// UseViewerFile *file;
GValue val G_VALUE_INIT;file g_object_new (VIEWER_TYPE_FILE, NULL);g_value_init (val, G_TYPE_UINT);
g_value_set_char (val, 11);g_object_set_property (G_OBJECT (file), zoom-level, val);g_value_unset (val);之前在介绍interface时有个完整的例子使用过属性。Gobject tutorial 六-CSDN博客
现在我们介绍一下属性。
Properties
属性功能是由Gobject系统提供的。属性本身都是各种类型的数据换句话说对于单一的属性它其实是一个类型的数据可以是char *也可以int,等等类型。属性是由对象实例维护当然这些对象实例都继承GObject。属性是按照名字来进行访问的且一个实例中的对象能够被其他实例访问。问题来了这个“共享“是怎么做到的我们后续会进行讨论。
在GObject中有很多方式可以设置和获取属性。
set方法有g_object_new、g_object_set, 后者是在应用中常用的方式。get方法中应用最常用的方式是g_object_get.
GtkWindow *win;
win g_object_new (GTK_TYPE_WINDOW, \title, Hello, \default-width, 800, \default-height, 600, NULL); 另一个使用方式如下 GtkWindow *win;
win g_object_new (GTK_TYPE_WINDOW, NULL);
g_object_set (win, title, Good bye, NULL);
那么如何获取呢
GtkWindow *win;
char *title;
int width, height;win g_object_new (GTK_TYPE_WINDOW, \title, Hello, \default-width, 800, \default-height, 600, NULL);
g_object_get (win, title, title, \default-width, width, \default-height, height, NULL);
g_print (%s, %d, %d\n, title, width, height);
g_free (title); GParamSpec
说到属性我们不得不对GParamSpec进行说明。GParamSpec是一个fundamental object, 它与GObject并无父子关系它的作用是保存参数的信息当然此处的参数也可以是属性。
我们看看它在属性注册过程中的作用。
/*gtk 4.8.2 demo3widget.c*/
static void
demo3_widget_class_init (Demo3WidgetClass *class)
{GObjectClass *object_class G_OBJECT_CLASS (class);
......object_class-dispose demo3_widget_dispose;object_class-set_property demo3_widget_set_property;object_class-get_property demo3_widget_get_property;......g_object_class_install_property (object_class, PROP_PAINTABLE,g_param_spec_object (paintable, Paintable, Paintable,GDK_TYPE_PAINTABLE,G_PARAM_READWRITE));g_object_class_install_property (object_class, PROP_SCALE,g_param_spec_float (scale, Scale, Scale,0.0, 10.0, 1.0,G_PARAM_READWRITE));......
}
注册 属性是通过函数g_object_class_install_property完成的新类型在注册时会实现自己的set_property/get_property函数如上面的demo3_widget_set_property/demo3_widget_get_property。
g_object_class_install_property函数的声明如下
void g_object_class_install_property (GObjectClass *oclass,guint property_id,GParamSpec *pspec)
既然在注册属性过程中GparamSpec是必须的那么就有必要对生成GParamSpec的函数进行说明我们以上例中的g_param_spec_float为例看看Glib的说明。
/*** g_param_spec_float:* name: canonical name of the property specified* nick: (nullable): nick name for the property specified* blurb: (nullable): description of the property specified* minimum: minimum value for the property specified* maximum: maximum value for the property specified* default_value: default value for the property specified* flags: flags for the property specified** Creates a new #GParamSpecFloat instance specifying a %G_TYPE_FLOAT property.** See g_param_spec_internal() for details on property names.** Returns: (transfer full): a newly created parameter specification*/
GParamSpec*
g_param_spec_float (const gchar *name,const gchar *nick,const gchar *blurb,gfloat minimum,gfloat maximum,gfloat default_value,GParamFlags flags) Overriding set_property and get_property class methods
重写set_property 、get_property的过程如下 对于不同的对象实例属性值是不同的因此属性值是存储在对象的实例中的。具体这是怎么做的呢。我们以上例中的demo3_widget_set_property为例进行说明。
static void
demo3_widget_set_property (GObject *object,guint prop_id,const GValue *value,GParamSpec *pspec)
{Demo3Widget *self DEMO3_WIDGET (object);switch (prop_id){case PROP_PAINTABLE:g_clear_object (self-paintable);self-paintable g_value_dup_object (value);gtk_widget_queue_resize (GTK_WIDGET (object));break;case PROP_SCALE:self-scale g_value_get_float (value);gtk_widget_queue_resize (GTK_WIDGET (object));break;default:G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);break;}
}
可以看到需要设置的属性值value,保存在self-paintable、self-scale中。Demo3Widget的定义如下
struct _Demo3Widget
{GtkWidget parent_instance;GdkPaintable *paintable;float scale;GtkWidget *menu;
};
Notify signal
还有一个重要的问题就是当设置属性后GObject会发出“notify信号。如果你在程序中给信号链接了处理函数你就能进行后续操作。notify信号在链接处理函数时是有格式要求的。如下
g_signal_connect (G_OBJECT (d1), notify::value, G_CALLBACK (notify_cb), NULL);
上面示例中“notify::value”中的value需要替换成属性名。如果不设置value,那么对象的任何属性被设置回调函数都会执行。 注意我们这里说当属性被设置时会发出notify 信号那么问题来了我为属性设置相同的值会不会有notify信号呢答案是会有的。那如果我想只在信号值发生改变时才受到notify信号该怎么办呢这种情况下首先我们在调用函数生成GParamSpec时为函数设置属性G_PARAM_EXPLICIT_NOTIFY标记具体来说对于上面提到的函数g_param_spec_float为例设置其最后的参数flag为G_PARAM_EXPLICIT_NOTIFY。其次需要在属性发生变化时手动调用函数g_object_notify_by_pspec来发送notify 信号。