【问题标题】:How to provide additional custom implementation of accessor methods when using @synthesize?使用@synthesize 时如何提供访问器方法的额外自定义实现?
【发布时间】:2009-08-20 15:18:42
【问题描述】:

我想在访问和更改属性时触发一些代码。我在我的 ivars 代码中使用 @property@synthesize。属性被保留了,所以我想保留@synthesize自动生成的内存管理东西。

但是,我假设@synthesize 告诉编译器在@synthesize is 的位置生成访问器方法代码,所以大多数情况都在代码的顶部,对吧?

当我有一个属性foo 时,我会得到-setFoo-foo 方法。然后我可以创建一个这样的方法,以便在更改属性时执行更多自定义代码吗?

-(void)setFoo {
    // custom stuff
}

现在这是一个问题。如何执行第一个?我不想在这里有一个不同的名字。有没有办法让@synthesize 指令为getter 和setter 方法创建其他名称,然后我可以轻松调用它们?而且我仍然可以使用点语法来访问它们吗?

【问题讨论】:

    标签: objective-c cocoa-touch cocoa accessor


    【解决方案1】:

    您可以像往常一样使用@property@synthesize,但提供自定义setter 或getter(或两者),然后使用它们。通常我会这样做:

    // Override the setter
    - (void)setName:(NSString *)aName
    {
        if (name == aName)
            return;
    
        [name release];
        name = [aName retain];
    
        //custom code here
    }
    

    当我使用 set 属性时,它会调用我的自定义方法。但是,get 仍然会被合成。

    【讨论】:

    • 仅供参考,您的示例设置器有一个错误,即使用同一个对象调用它两次可能会导致该对象在保留之前被释放。没什么大不了的,但它说明了要完全正确地完成这些事情是多么困难。
    • 我不确定我是否遵循,你能解释一下它应该如何写吗(不是我不相信你,我想知道如何正确地做到这一点)。谢谢:)
    • 哦,nvm 我看到了问题,我会更新它以反映变化。
    • 另一种避免 if 语句的方法是:[aName retain]; [名称发布]; name = aName;
    • if 语句会更快吗?它只是比较两个指针并可能提前返回。替代方案在哪里调用这两种方法,然后不管分配? (我知道从长远来看这没什么大不了的)
    【解决方案2】:

    如果您为 setter 或 getter 提供实现,它将使用它而不是生成的实现。实现编译器在合成时为您生成的 getter 和 setter 的“保留”方面并不难,因此您可以编写自己的 getter 和 setter,我会说并继续使用。

    【讨论】:

      【解决方案3】:

      一个古怪的解决方案是创建一个抽象超类,它可以为您提供正常的属性综合。 然后创建一个您将实际使用的具体子类,它只是实现和覆盖方法(相同的签名)并调用 super 来进行实际设置。 这允许你在调用 super 的实现之前或之后做任何你想做的事情。

      例子:

      @interface ALTOClassA : NSObject
      
      
      @property NSString *catName;
      
      @end
      

      除了这个测试的存根文件之外,.m 中不需要其他任何东西。

      创建子类,@interface 不需要特别的东西

      #import "ALTOClassA.h"
      
      @interface ALTOClassAJunior : ALTOClassA
      
      @end
      

      在@implementation 中,我们进行覆盖。

      #import "ALTOClassAJunior.h"
      
      @implementation ALTOClassAJunior
      
      
      - (void)setCatName:(NSString*)aCatName {
          NSLog(@"%@",NSStringFromSelector(_cmd));
          [super setCatName:aCatName];
          NSLog(@"after super: self.catName %@", self.catName);
      }
      @end
      

      使用中:

          ALTOClassAJunior *aCAJ = [ALTOClassAJunior new];
      NSLog(@"aCAS.catName %@", aCAJ.catName);
      
      NSLog(@"set it to George.");
      
      [aCAJ setCatName:@"George"];
      
      NSLog(@"aCAS.catName %@", aCAJ.catName);
      

      这允许您利用自动生成的代码,并且仍然可以对您的课程做您想做的事情。抽象超类通常是许多事情的有用解决方案。

      【讨论】:

        【解决方案4】:

        是的,在您的@property 声明中,您可以指定getter 和setter 方法。

        @property (readwrite,getter=privateGetFoo,setter=privateSetFoo:) NSObject * foo;
        

        在您的foosetFoo: 方法中,调用[self privateGetFoo][self privateSetFoo:f],然后调用您的自定义代码。

        该对象还可以使用addObserver:forKeyPath:options:context: 为其自身设置一个观察者。

        也就是说,我认为这两种方式都不是很干净的做事方式。最好按照其他人的建议编写自己的 getter/setter。

        【讨论】:

        • 您说:“在您的 foo 和 setFoo: 方法中...” 虽然 [obj setFoo: x] 和 [obj foo] 可用,但需要注意的是,由于修改了属性, obj.foo 将不可用于写入,您必须使用 obj.setFoo = x。这不是@property 通常这样做的方式,其中 obj.foo 用于读取和写入。
        • 那么 object.foo 等价于 [object privateFoo],这违背了使用属性的全部目的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多