在属性声明中,原子和非原子意味着什么?

@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;

这三者之间的操作差异是什么?


当前回答

苹果的文档中对此进行了解释,但下面是一些实际发生情况的示例。

请注意,没有“atomic”关键字,如果不指定“nonatomic(非原子)”,则属性是原子的,但显式指定“atomic”将导致错误。

如果不指定“非原子”,则该属性是原子的,但如果需要,在最近的版本中仍然可以显式指定“原子”。

//@property(nonatomic, retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    return userName;
}

- (void) setUserName:(UITextField *)userName_ {
    [userName_ retain];
    [userName release];
    userName = userName_;
}

现在,原子变体有点复杂:

//@property(retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    UITextField *retval = nil;
    @synchronized(self) {
        retval = [[userName retain] autorelease];
    }
    return retval;
}

- (void) setUserName:(UITextField *)userName_ {
    @synchronized(self) {
      [userName_ retain];
      [userName release];
      userName = userName_;
    }
}

基本上,原子版本必须使用锁以保证线程安全,并且还会碰撞对象上的引用计数(以及自动释放计数以平衡它),从而保证该对象对于调用者存在,否则如果另一个线程正在设置该值,则存在潜在的争用条件,导致引用计数降至0。

实际上,根据财产是标量值还是对象,以及保留、复制、只读、非原子等交互方式,这些东西的工作方式有很多不同的变体。一般来说,属性合成器只知道如何为所有组合做“正确的事情”。

其他回答

在阅读了这么多文章、StackOverflow文章和制作用于检查变量属性的演示应用程序后,我决定将所有属性信息放在一起:

atomic//默认非原子的strong=保留//默认弱=未染色保持分配//默认值未染色的复制只读的readwrite//默认

在iOS中的可变属性属性或修饰符一文中,您可以找到上述所有属性,这肯定会对您有所帮助。

原子的原子意味着只有一个线程访问变量(静态类型)。atomic是线程安全的。但它的性能很慢原子是默认行为非垃圾收集环境中的原子访问器(即,当使用retain/release/autorelease时)将使用锁来确保另一个线程不会干扰值的正确设置/获取。它实际上不是一个关键字。例子:@属性(retain)NSString*name;@综合名称;非原子的非原子意味着多线程访问变量(动态类型)。非原子是线程不安全的。但它的性能很快非原子不是默认行为。我们需要在属性属性中添加非原子关键字。当两个不同的进程(线程)同时访问同一变量时,可能会导致意外行为。例子:@属性(非原子,保留)NSString*name;@综合名称;

事实是,他们使用自旋锁来实现原子属性。代码如下:

 static inline void reallySetProperty(id self, SEL _cmd, id newValue, 
      ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) 
    {
        id oldValue;
        id *slot = (id*) ((char*)self + offset);

        if (copy) {
            newValue = [newValue copyWithZone:NULL];
        } else if (mutableCopy) {
            newValue = [newValue mutableCopyWithZone:NULL];
        } else {
            if (*slot == newValue) return;
            newValue = objc_retain(newValue);
        }

        if (!atomic) {
            oldValue = *slot;
            *slot = newValue;
        } else {
            spin_lock_t *slotlock = &PropertyLocks[GOODHASH(slot)];
            _spin_lock(slotlock);
            oldValue = *slot;
            *slot = newValue;        
            _spin_unlock(slotlock);
        }

        objc_release(oldValue);
    }

在单行中:

原子是线程安全的。非原子是线程不安全的。

原子:

原子保证以原子的方式访问财产。例如,它总是返回一个完全初始化的对象,一个线程上的属性的任何获取/设置都必须在另一个线程访问它之前完成。

如果你想象一下下面的函数同时出现在两个线程上,你就会明白为什么结果不好看。

-(void) setName:(NSString*)string
{
  if (name)
  {
    [name release]; 
    // what happens if the second thread jumps in now !?
    // name may be deleted, but our 'name' variable is still set!
    name = nil;
  }

  ...
}

赞成的意见:每次返回完全初始化的对象是多线程情况下的最佳选择。

欺骗:性能受到影响,执行速度稍慢

非原子:

与Atomic不同,它不能确保每次都返回完全初始化的对象。

赞成的意见:执行速度极快。

欺骗:在多线程的情况下,可能会产生垃圾值。

原子意味着一次只能有一个线程访问变量(静态类型)。原子是线程安全的,但它很慢。

非原子意味着多个线程可以同时访问变量(动态类型)。非原子线程不安全,但速度很快。