精华内容
下载资源
问答
  • 修改属性声明为readonly的属性

    千次阅读 2018-07-01 13:37:15
    修改属性声明为readonly的属性值 在NSOperation中,executing、finished等属性都被声明为readonly,但在继承NSOperation的子类中,可能需要修改这些属性的值,该如何处理呢? 可在子类中添加如下的代码: @...

    修改属性声明为readonly的属性值

    NSOperation中,executingfinished等属性都被声明为readonly,但在继承NSOperation的子类中,可能需要修改这些属性的值,该如何处理呢?

    可在子类中添加如下的代码:

    @synthesize executing = _executing;
    @synthesize finished = _finished;

    可参考:Overriding readonly property in subclass


    iOS修改声明为readonly的属性值

    转载自iOS修改声明为readonly的属性值

    本文讨论的是,对于类中声明为 readonly 的属性值,我们就不可以修改其值了么?如何可以,那么如何修改呢?

    为了便于说明,定义一个 ACLStudent 的类:

    ACLStudent.h
    
    @interface ACLStudent : NSObject
    
    @property (nonatomic, assign, readonly) NSInteger studentId;
    @property (nonatomic, copy, readonly) NSString *firstName;
    @property (nonatomic, copy, readonly) NSString *lastName;
    
    - (instancetype)initWithStudentId:(NSInteger)studentId firstName:(NSString *)firstName lastName:(NSString *)lastName;
    
    @end
    
    --------------------------
    
    ACLStudent.m
    
    @implementation ACLStudent
    
    - (instancetype)initWithStudentId:(NSInteger)studentId firstName:(NSString *)firstName lastName:(NSString *)lastName {
        self = [super init];
        if (self) {
            _studentId = studentId;
            _firstName = [firstName copy];
            _lastName = [lastName copy];
        }
    
        return self;
    }
    
    @end

    接下来定义一个 ACLStudent 类的对象:

    ACLStudent *student = [[ACLStudent alloc] initWithStudentId:1 firstName:@"Carya" lastName:@"Liu"];
    NSLog(@"student firstName: %@", student.firstName);

    现在我们考虑的就是如何修改 student 对象的 firstName 属性值为@"Qiu"

    如果直接调用 firstNamesetter 方法,student.firstName = @"Qiu", 那么就直接报错,提示不能够给声明为 readonly 的属性赋值。那么使用 KVC 呢?

    [student setValue:@"Qiu" forKey:NSStringFromSelector(@selector(firstName))];
    NSLog(@"student firstName after changed: %@", student.firstName);

    运行,发现属性值被成功修改。哈哈,那么现在来看看 KVC 为什么能够修改该属性值呢?看看文档 Accessor Search Implementation Details

    当使用 setValue:forKey: 来设置对象的属性时,会以下面的优先顺序来寻找对应的 key:

    1. 消息接收对象会查找是否存在满足 set<Key>: 格式的存取方法。
    2. 如果不存在满足条件的存取方法,且消息接收对象的类方法 + (BOOL)accessInstanceVariablesDirectly 返回 YES,那么该对象会以 _<key>, _is<Key>, <key>, is<Key> 的顺序查找是否存在对应的key。
    3. 如果存在对应的存取方法或者找到对应的实例变量,那么就会改变该 key 所对应的值 value。必要的话,value 所对应的值会从对象中解析出来,如 Representing Non-Object Values 所描述的那样。
    4. 如果没有找到对应的存取方法或者实例变量,那么该消息对象的 setValue:forUndefinedKey: 将会调用。

    5. 对于上述第2点说明一下,如果我们不想让 setValue:forKey: 方法改变对象的属性值,那么重写其类方法 + (BOOL)accessInstanceVariablesDirectly 返回 NO (该方法默认返回 YES,即在不存在满足条件的存取方法时,允许直接访问属性对应的实例变量);在搜索实例变量时,会首先检查带下划线的实例变量,然后检查不带下划线的实例变量。

    对于上述第3点举例说明,如果修改 student 对象的属性 NSInteger studentId, 注意其是 NSInteger 类型,我们在调用 setValue:forKey: 方法时可以像这样

    [student setValue:@(20) forKey:NSStringFromSelector(@selector(studentId))];

    传入一个 NSNumber 对象也可以,Objective-C 会处理好一切。

    对于上面的示例,使用 setValue:forKey: 实际修改的是 student 实例中 _firstName 实例变量的值。不要忘记,我们在声明一个 firstName 的属性时,编译器会为我们自动合成一个 _firstName 的实例变量。

    总结:

    • 当我们声明一个 readonly 的属性,外部可能会通过 KVC 修改该属性值。
    • 为了避免 KVC 修改属性值,须将定义属性所在类的类方法 + (BOOL)accessInstanceVariablesDirectly 重写,使其返回 NO.
    展开全文
  • 用了两天好好的研究了一下runtime,之前初涉runtime。懵懵懂懂的了解runtime的...主要涉及的就是获取并修改属性。添加并修改私有方法。好了,首先说一下如何获取属性值。如果需要获取某个属性,我们最先需要知道你想获

    用了两天好好的研究了一下runtime,之前初涉runtime。懵懵懂懂的了解runtime的强大,但是如何的强大,只是在demo中引用MJExtension的时候自动生成model,了解了一些。
    经过一天半的研究,首先温习了之前的获取属性列表。

    今天想说的具体功能如题所述。主要涉及的就是获取并修改属性。添加并修改私有方法。

    好了,首先说一下如何获取属性值。如果需要获取某个属性,我们最先需要知道你想获取的类的名字。如果我们只有某一个类的字符串,同样可以达到目的,这也就是runtime的神奇之处。

    (1)例如我们想要得到UserInfo这个类下的所有属性。但是现在只有字符串className=@"UserInfo",我们可以用最常见的runtime语句去获取到class。如下:Class UserInfo = NSClassFromString(className);这时候我们就得到了这个类。但是这时的UserInfo相当于没有alloc的类。

    (2)我们在网上有两种方式可以获取到属性的name,type以及value。第一种方式如下:

    - (NSArray*)getAllPropertyName//runtime获取model所有属性
    {
        NSMutableArray* nameArray = [NSMutableArray array];
        unsigned int count = 0;
        objc_property_t *property_t = class_copyPropertyList([UserInfo class], &count);
        for (int i=0; i<count; i++) {
            objc_property_t propert = property_t[i];
            const char * propertyName = property_getName(propert);
            [nameArray addObject:[NSString stringWithUTF8String:propertyName]];
        }
        free(property_t);
        return nameArray;
    }

    上面只是获取到属性名,如果想要获取其它的东西,也可以自行查询方法。不过目前只有这个有点用。
    第二种方法如下:

        unsigned int countNum = 0;
        Ivar *members = class_copyIvarList([self.panoramView class], &countNum);
        for (int i=0; i<countNum; i++) {
            Ivar var = members[i];
            const char *memberName = ivar_getName(var);
            //属性描述
            NSString *memberStr = [NSString stringWithFormat:@"%s",memberName];
            if ([memberStr isEqualToString:@"_advsObject"]) {
                const char * type = ivar_getTypeEncoding(var);
            }
        }
    

    上面的方法获取到的属性是C的格式,需要转变成OC,所以中间写了一个memberStr作为媒介。

    以上就是获取属性的方法,下面说下如何修改属性内容。

    (3)其实修改属性的方法,很简单,就一句话,一共有三个参数。object_setIvar(id obj, Ivar ivar, id value)
    *@param obj The object containing the instance variable whose value you want to set.
    * @param ivar The Ivar describing the instance variable whose value you want to set.
    * @param value The new value for the instance variable.*这是官方给的解释。

    我们根据以上的三个参数,对其进行赋值,如下:object_setIvar(self.userInfo, var, @"改过的内容");
    到此:属性的修改就结束了。今天写这篇文章,主要是为了记录如何修改私有方法的。所以接下来才是重头戏。

    如果我们要修改某一个类库的私有方法,当然,通过runtime都是为了修改私有方法的,毕竟非私有方法,又何必用runtime这个繁琐的东西呢。我这里的需求说起来还是被第三方深恶痛绝的,但是对一些技术还处在一个瓶颈,无法越过的同学们是一个福音。
    我的需求就是,下载的第三方,为了防止我们滥用他们的劳动成果,也或者为了获得一定的报酬,所以才在代码中封装一个明显的lable或者context等控件悬浮在view上。我就是要把他悬浮的这个控件屏蔽掉,或者隐藏或者remove掉,期初想用KVO,直接setvalue:hidden的,但是由于这个控件是私有变量,所以无法直接使用KVO访问的。最终选择了使用runtime修改私有方法即可。

    (4)同样我们需要知道要修改的类的名字,然后获取该类下的所有方法。代码如下:

    -(NSArray *)getAllMethods
    {
        unsigned int count_f =0;
        //获取方法链表
        Method* methodList_f = class_copyMethodList([UserInfo class],&count_f);
    
        NSMutableArray *methodsArray = [NSMutableArray arrayWithCapacity:count_f];
    
        for(int i=0;i<count_f;i++)
        {
            Method temp_f = methodList_f[i];
            //方法的调用地址
            IMP imp_f = method_getImplementation(temp_f);
            //方法
            SEL name_f = method_getName(temp_f);
            //方法名字符串
            const char* name_s =sel_getName(method_getName(temp_f));
            //参数数量
            int arguments = method_getNumberOfArguments(temp_f);
            //返回方法的参数和返回值的描述的字串
            const char* encoding =method_getTypeEncoding(temp_f);
            NSLog(@"方法名:%@,参数个数:%d,编码方式:%@",[NSString stringWithUTF8String:name_s],
                  arguments,[NSString stringWithUTF8String:encoding]);
    
            NSString *methodStr = NSStringFromSelector(name_f);
    
            [methodsArray addObject:methodStr];
    
        }
        free(methodList_f);
    
        return methodsArray;
    }

    以上就是获取的该类下的所有方法,这个时候我们就该猜了,这是一个痛苦的过程,因为我们不知道到底哪个方法是我们需要修改的。但是一般开发者命名的时候是会根据需要做的意思而命名的,我们只能这样缩小范围了,但是如果真的碰到了加密的方法,或者说命名方法没有规律的,那我真的没办法了。只能一个一个试试了。

    (5)如果我们搜索到了方法名为:setUserName:我们需要添加方法,然后再修改这个私有方法的回调。

    -(void)laodNewMethod
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            Class class = [UserInfo class];
            //原来的方法
            SEL originalSelector = @selector(setUserName:);
            //新方法
            SEL swizzledSelector = @selector(setNewUserName:);
            //原来的Method
            Method originalMethod = class_getInstanceMethod(class, originalSelector);
            //新Method
            Method swizzledMethod = class_getInstanceMethod([self class], swizzledSelector);
            //添加到runtime新方法
            BOOL didAddMethod =class_addMethod(class,originalSelector,method_getImplementation(swizzledMethod),method_getTypeEncoding(swizzledMethod));
            if (didAddMethod) {
                class_replaceMethod([self class],swizzledSelector,method_getImplementation(originalMethod),method_getTypeEncoding(originalMethod));
            } else {
                method_exchangeImplementations(originalMethod, swizzledMethod);
            }
    
    
        });
    }
    -(void)setNewUserName:(NSString *)newUserName
    {
        NSlog("这里就是修改后的方法,每次运行都会自动跳到这里调用这个方法了。")
    }

    以上就是所有今天关于runtime的内容

    展开全文
  • java反射修改属性

    千次阅读 2020-09-03 13:42:30
    * java反射修改属性值 */ import java.lang.reflect.Field; public class FinalTest { private final double a; { Class<FinalTest> aClass = FinalTest.class; Field field = null; try { f
    package com.mtons.mblog;
    
    /**
     * java反射修改属性值
     */
    
    import java.lang.reflect.Field;
    
    public class FinalTest {
    
        private final double a;
    
        {
            Class<FinalTest> aClass = FinalTest.class;
            Field field = null;
            try {
                field = aClass.getDeclaredField("a");
                field.setAccessible(true);
                // field.set(this, 1000.0);
                Object o = field.get(this);
                System.err.println(o);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    
        public FinalTest() {
            this.a = 10.0;
        }
    
        public static void main(String[] args) throws Exception {
            FinalTest test = new FinalTest();
            System.out.println(test.a);
        }
    
    }
    
    
    展开全文
  • 利用java反射机制修改属性

    千次阅读 2020-06-18 22:34:40
    利用java反射机制修改属性

    利用java反射机制修改属性值

    本文将介绍如何利用java反射机制修改属性值,废话不多说,直接上代码
    1、新建一个实体类,添加属性test以及获取属性值的方法getTest()

    public class ReflectTest {
        //测试修改属性
        String test = "修改前的值";
        public String getTest(){
            return test;
        }
    }
    

    2、新建一个测试类,利用反射机制获取类对象、方法、属性,方法对象调用invoke()执行方法

    class Test{
        public static void main(String[] args) throws Exception {
            //获取ReflectTest类的class对象
            Class<ReflectTest> reflectTestClass = ReflectTest.class;
            //获取实例对象
            ReflectTest reflectTest = reflectTestClass.newInstance();
            //获取属性对象
            Field testField = reflectTestClass.getDeclaredField("test");
            //获取方法对象
            Method getTestMethod = reflectTestClass.getDeclaredMethod("getTest", null);
            //执行方法
            Object invoke = getTestMethod.invoke(reflectTest);
            System.out.println(invoke);
        }
    }
    

    修改前得到的打印结果如下
    以上为打印结果
    3、以上为默认修饰符属性未修改的情况,现在我们通过testField.set(reflectTest,“修改后的值”)修改属性值;修改默认属性代码如下:

    //获取ReflectTest类的class对象
    Class<ReflectTest> reflectTestClass = ReflectTest.class;
    //获取实例对象
    ReflectTest reflectTest = reflectTestClass.newInstance();
    //获取属性对象
    Field testField = reflectTestClass.getDeclaredField("test");
    //修改属性值
    testField.set(reflectTest,"修改后的值");
    //获取方法对象
    Method getTestMethod = reflectTestClass.getDeclaredMethod("getTest", null);
    //执行方法
    Object invoke = getTestMethod.invoke(reflectTest);
    System.out.println(invoke);
    

    修改后打印结果如下:
    在这里插入图片描述
    4、默认属性可以修改,那么其他属型呢?我们依次试试public、protected,修改后打印结果均为“修改后的值”。修改private修饰的属性值时却抛出异常IllegalAccessException。原来,在利用反射机制修改私有属性的值前,需要执行setAccessible(true),这样就能绕过private的限制啦,改动代码和结果如下:

    //获取属性对象
    Field testField = reflectTestClass.getDeclaredField(“test”);
    testField.setAccessible(true);
    //修改属性值
    testField.set(reflectTest,“修改后的值”);

    打印结果:
    在这里插入图片描述
    5、默认、public、protected、private都修改成功了,那么如果都换成静态修饰的呢?小编一一测试之后依然是能够实现的。那么final修饰的属性是否能够被修改呢?
    这里首先将属性改为final修饰:

    private final String test = “修改前的值”;

    修改属性的代码不变:

    //获取属性对象
      Field testField = reflectTestClass.getDeclaredField("test");
      testField.setAccessible(true);
      //修改属性值
      testField.set(reflectTest,"修改后的值");
      //获取方法对象
      Method getTestMethod = reflectTestClass.getDeclaredMethod("getTest", null);
      //执行方法
      Object invoke = getTestMethod.invoke(reflectTest);
      System.out.println(invoke);
    

    得到的结果如下,仍然是修改前的值:
    在这里插入图片描述
    这里可以看见我们打印类的属性值并没有改变,当前反射获取到的属性值却发生了改变,代码和结果如下:

    //获取属性对象
      Field testField = reflectTestClass.getDeclaredField("test");
      testField.setAccessible(true);
      //修改属性值
      testField.set(reflectTest,"修改后的值");
      System.out.println(testField.get(reflectTest));
    

    执行以上代码结果如下:
    在这里插入图片描述
    6、为了修改final修饰的类属性的值,我们要对 Java 反射包中的类进行自我反射。Field 对象有个一个属性叫做 modifiers, 它表示的是属性是否是 public, private, static, final 等修饰的组合。这里把这个 modifiers 也反射出来,进而把 nameField 的 final 约束去掉。代码如下:

    //获取ReflectTest类的class对象
    Class<ReflectTest> reflectTestClass = ReflectTest.class;
    //获取实例对象
    ReflectTest reflectTest = reflectTestClass.newInstance();
    //获取属性对象
    Field testField = reflectTestClass.getDeclaredField("test");
    //获取modifiers属性,modifiers属性也是私有的
    Field modifiers = Field.class.getDeclaredField("modifiers");
    modifiers.setAccessible(true);
    //改掉testField属性的modifiers 值  按位取反再按位与 操作把 final 从修饰集中剔除掉,
    // 其他特性如 private, static 保持不变
    modifiers.setInt(testField,testField.getModifiers() & ~Modifier.FINAL);
    testField.setAccessible(true);
    //修改属性值
    testField.set(reflectTest,"修改后的值");
    //获取方法对象
    Method getTestMethod = reflectTestClass.getDeclaredMethod("getTest", null);
    //执行方法
    Object invoke = getTestMethod.invoke(reflectTest);
    System.out.println(invoke);
    

    此时运行程序没有报错,但打印出来的还是修改前的值,原因是编译期间final类型的数据自动被优化,“修改前的值”是直接在常量区内取的值,我们将其换成基本数据类型也是一样,均是取得常量区的值。而使用new String(“修改前的值”)进行初始化编译期间不会被优化:

    private final String test = new String(“修改前的值”);

    打印结果:
    在这里插入图片描述
    本期分享就结束啦,楼主是个萌新,初次编写文章,如有不对的地方,欢迎大家留言指正哦。

    展开全文
  • js 对象数组添加属性修改属性

    万次阅读 2018-10-12 19:24:14
    //修改属性 return rObj; }); console.log(reformattedArray); var reformattedArray2 = kvArray.map(function(obj,index) { obj.id=index;//添加id属性 return obj;//如果不返回则输出: Array [undefined, ...
  • JQ设置更改属性和属性值

    千次阅读 2017-07-25 19:11:29
    html> html lang="en"> head> meta charset="UTF-8"> title>Titletitle> script src="jquery-3.1.1.min.js">script> head> body> input type="text"name="123"value=""> body> ...// 获取name属性
  • jQuery修改属性

    千次阅读 2018-05-11 21:06:41
    1. attr()函数获取标签的某个属性值$('... attr( )添加标签的属性注:原有标签属性没有的话, 会添加修改后的标签属性$('#id定位标签').attr('原有属性', '修改后的属性')有则改之, 无则添之4. 删除某个属性$('#id...
  • Vue获取DOM元素并修改属性

    万次阅读 2019-07-16 13:48:23
    Vue获取DOM元素 Vue获取DOM元素有两种方法 直接给相应的元素加id,然后再使用document....Vue获取到元素并修改属性或者样式 使用上述的第二种方法,获取到元素,然后使用this.$refs.元素元素的ref对应的name.style...
  • 找到元素后,我们可以利用getAttribute()方法把它的各种属性的值查询出来; 将不含title属性的p标签过滤掉,怎么做? setAttribute()方法修改属性值 ...
  • jquery修改属性

    万次阅读 2018-05-19 12:46:46
    2.attr()修改修改标签的属性值 //如果存在就是修改,如果不存在就是添加 $('#p').attr('class','red') 3. 删除某个属性 $('#p').removeAttr('name') 4.添加class名称 $('#p').a...
  • JS修改属性名的尴尬

    2019-07-16 11:25:34
    今天碰到需要修改属性名的问题,比如将下面这个对象: var obj = { 'myName': 'XiaoMing', 'myAge': 12, } 修改为: var obj = { 'yourName': 'XiaoMing', 'myAge': 12, } 在网上搜了一个方法: obj = ...
  • Jquery 更改属性attr()

    2015-11-18 16:03:04
    1.1 Jquery 更改属性attr() 作用:  attr() 方法设置或返回被选元素的一个或多个属性。 1.返回 attr属性 attr("propertyname"); 2.设置 attr属性 attr("propertyname","value"); 3.设置多个 attr ...
  • 我们将属性和方法封装到类中,可以通过实例直接修改属性值,也可以创建更新属性的方法。 class stars(): '''描述娱乐圈明星''' def __init__(self,name,age,high,famous): self.name=name self.age=age self...
  • PB数据窗口对象之字段的修改属性

    千次阅读 2014-07-04 11:00:51
    当数据窗口的数据来源于不止一个数据表时,可以用脚本控制数据窗口的修改属性来对数据表逐个进行修改。 当数据窗口是用来接受用户的手工录入数据时,应该设置两方面的属性才能确保数据窗口能够用来修改数据表。一个...
  • nifi更改属性的方法——UpdateAttribute

    千次阅读 2016-04-28 18:16:49
    在nifi中FlowFile的组成包括属性和内容两部分: 属性:给用户数据提供上...在nifi中更改属性的方法有三种,分别是 1. Basic Usage:更改经过这个Processor的FlowFile的默认属性。 2. Advanced Usage:这个允许更改
  • wpf,自定义控件属性,可以在xaml里设置,那么怎样在c#里修改属性?我自定义了datepicker的一个属性,现在想用c#来后台修改(当触发时间时),求大牛解答
  • json数组遍历并修改属性

    千次阅读 2018-12-13 10:38:44
    json数组,修改属性名 不多说,直接上代码。 //把“name”属性修改为“title”,并删除“name”这一项 var json = [ {id:0,name:'aa'}, {id:1,name:'bb'}, {id:2,name:'cc'}, {id:3,name:'dd'}, {id:4,name:'...
  • 传奇修改属性

    千次阅读 2015-10-28 16:50:21
    如果是@make就是制造命令 比如制造三把屠龙就输入@make 屠龙 3 中间有空格修改装备属性 需要拿在手上@supermake 0 0 255 第一个数字:0.代表衣服1.代表武器2代表勋章3代表项链4代表头盔5代表右手镯6代表左手镯7代表...
  • vue子组件更改属性

    千次阅读 2019-06-15 16:51:00
    严格来说,Vue子组件不能随便更改父组件传递过来的属性,但是可以这样修改 父组件 1 <component-a :num.sync="number">这是子组件</component-a> 子组件 1 <template> 2 <div> ...
  • DOM 修改属性简单操作

    千次阅读 2020-08-06 11:21:03
    文章目录属性操作非表单元素的属性表单元素属性案例自定义属性操作样式操作类名操作案例 属性操作 非表单元素的属性 href、title、id、src、className var link = document.getElementById('link'); console.log...
  • js 更改属性值的方法

    千次阅读 2019-06-24 17:12:00
    object.defineProperty...// 添加或更改多个对象属性 Object.defineProperties(object, descriptors) // 访问属性 Object.getOwnPropertyDescriptor(object, property) // 以数组返回所有属性 Object.getOwnPr...
  • 【PB】数据窗口的修改属性

    千次阅读 2016-03-21 15:30:10
    数据窗口对象非常强大的原因之一就是能够很容易地修改数据库。当用户修改了数据窗口中的数据,插入了新的数据行...当数据窗口的数据来源于不止一个数据表时,可以用脚本控制数据窗口的修改属性来对数据表逐个进行修改
  • 3,修改属性值 1,简单使用 他这个@Builder注解,相比之前的编辑器自动生成的getter setter的优点在哪呢? 看下面的使用例子 package com.lxk.lombok; import com.lxk.model.Bird; import java.util.Date; ...
  • Altium Designer 批量修改属性

    千次阅读 2011-07-27 11:16:18
    Altium Designer 批量修改属性2010-07-15 11:23:17| 分类: 电路设计 | 标签: |字号大中小 订阅 下面这部分是我转载在网上其它地方查到的内容:http://hi.baidu.com/hellowsn/blog/item/8d93b2179
  • java写的文件属性显示以及修改属性

    千次阅读 2018-03-12 19:28:10
    java写的文件属性显示import java.awt.Container;import javax.swing.*;import java.awt.BorderLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.File;import java....
  • arcgis批量修改属性

    千次阅读 2016-11-22 17:19:25
    arcgis作为GIS领域应用最广泛的软件,在GIS从业人员的日常工作中必不可少。本文主要介绍arcgis属性属性通改的一个快捷方法,只需要简单的VB代码就能大幅度提高修改效率。下图所示为示例属性表: 某...
  • Arcgis属性表怎么添加字段? 在arcgis工作中很多时候我们需要对属性表进行添加字段的操作。下面我们讲一下如何在属性表中添加字段。 打开一个arcgis工程文件,打开某一要素的属性表。 点击左上角的按钮,在下拉菜单...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,474,751
精华内容 989,900
关键字:

修改属性