7

EDIT: This question applies to normal declared properties as well (not only to class properties)!

Original Post:

Lets say I have the public class method sharedInstance which is currently implemented as a getter method:

@interface MyClass

+ (instancetype)sharedInstance;

- (void)doSomething;

@end

@implementation MyClass

+ (instancetype)sharedInstance {
    static MyClass *shared = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        shared = [[MyClass alloc] init];
    });
    return shared;
}

@end

Accessing this method in Swift 3.0 would look like this: MyClass.shared().doSomething()

So to make it more swifty we should change the class method to a class property (new in Xcode 8. but actually I can't find it in the Apple Docu, only in WWDC 2016 video)

@interface MyClass

@property (class, nonatomic, readonly) MyClass *sharedInstance;

- (void)doSomething;

@end

// implementation stays the same

Now in Swift code: MyClass.shared.doSomething()

So does nonatomic/atomic property modifier (don't know the exact term) even makes sense for a getter method which I implement myself in objc?

Buju
  • 1,546
  • 3
  • 16
  • 27
  • Atomic vs. non-atomic has to do with the way the compiler generates code to handle concurrent access to the property. If you use atomic properties, the compiler surrounds read/write accesses to the property with a lock to avoid read/write collisions. If the property gets modified ANYWHERE (including using the backing instance variable from inside the class) and the instance of the class can be accessed from other threads, you should probably leave it atomic. – Duncan C Nov 07 '16 at 18:43
  • I don't see how you could convert an Objective-C class method for a singleton to an Objective-C property. The code you posted in the second part of your question is a normal instance property, so it would not work to access a singleton. – Duncan C Nov 07 '16 at 18:47
  • 1
    @duncanc: `@property (class)` makes it a class property, not an instance property. This has no effect on ObjC access, but changes the Swift syntax. – rickster Nov 07 '16 at 18:48
  • But how will making it a class property allow you to invoke code that creates the singleton the first time and returns it thereafter? – Duncan C Nov 07 '16 at 18:50
  • 1
    Ah, there does seem to be a bug in the OP's code that the method is spelled `sharedInstance` at declaration and `sharedService` at implementation. For this to work as intended it needs to be the same in both places. – rickster Nov 07 '16 at 18:51
  • 2
    For some reason only known to Apple, "atomic" is the default. However, it is slower and it would be very rare that it does anything helpful. Use nonatomic. – gnasher729 Nov 07 '16 at 18:59
  • As noted in my answer, atomic/nonatomic has no effect *in this case*, which means not specifying atomicity at all also has no effect. @gnasher729: The performance/safety considerations for `atomic` are most pronounced on mobile devices, so there's a strong tradition of using the `NS_NONATOMIC_IOSONLY` macro in cross platform code. – rickster Nov 07 '16 at 19:07
  • sry, I fixed the example code :) – Buju Nov 07 '16 at 19:45

2 Answers2

5

The atomic/nonatomic modifiers have no effect in your case, for multiple reasons.

The main reason is that atomicity keywords affect only generated code (i.e. synthesized accessor methods). When you declare a @property in your interface and then implement it with a method (or method pair) in your implementation, the compiler isn't generating code, so your atomicity keyword is ignored.

There are a few ways to get to this situation, and you're triggering a couple of them:

  • First, you have a class property. The compiler can't synthesize accessors or storage for class properties — which means no code generation, so atomicity doesn't apply.

  • Second, in most common uses of readonly properties, the @property declaration is backed by a manually implemented getter method — which means there's no code generation and thus atomicity doesn't apply.

    (Note you can also have instance properties declared as readonly in a public interface and synthesized due to a private readwrite redeclaration in your implementation. In that case, not only does atomicity apply, you have to make the atomicity keywords match between your public and private declarations. You can also synthesize just a getter and work directly with the backing ivar in your implementation.)

Because specifying either atomic or nonatomic for this property does nothing either way, you're free to just leave atomicity keywords out of your declaration entirely. (The compiler will assume atomic, but as noted that assumption has no effect.)

rickster
  • 124,678
  • 26
  • 272
  • 326
  • You are overlooking one possibility - the property could be redeclared `readwrite` privately in the class extension. And it may make sense for the `readwrite` property to be atomic which means it makes sense for the `readonly` public declaration to also be `atomic`. – rmaddy Nov 07 '16 at 19:13
  • The modifier `atomic` takes effect on readonly properties. A synthesized atomic getter puts the returned value in the autorelease pool. A readonly property without setter could have useful generated getter too, because the implementation can assign to the ivar. – clemens Nov 07 '16 at 19:27
  • @macmoonshine: Again, `atomic` affects only synthesized code. You can't have a synthesized getter unless you also have a synthesized setter somewhere. When `readonly` is merely a declaration that you have a manually implemented getter, atomicity keywords don't apply. – rickster Nov 07 '16 at 19:36
  • 2
    @rickster: This is not true. You can have a synthesized getter with no setter. You can always write the value over the synthesized ivar. Synthesizing a readonly property is the default, if you define no getter. – clemens Nov 07 '16 at 19:43
  • @rickster thx for confirming my suspicions. I also came to the same conclusion, but wasn't really sure. thats why I asked here. So yes, atomicity keywords are ignored once you implement your own getter/setter for that property. It is only really important for generated code by the compiler. – Buju Nov 07 '16 at 19:44
  • 1
    @macmoonshine: Ah, I'd forgotten some of the less common permutations. Edited the answer for clarity... but the key point remains: if you don't have synthesized code, atomicity keywords do nothing. – rickster Nov 07 '16 at 19:45
  • Beside this, the attributes of property *declaration* has semantic meanings. This is, why it is a part of the declaration. Even you write your own getter (and/or setter), the ability of atomicity should be reflected in the declared property. This is more than "doesn't apply". It doesn't apply *automatically*, but should apply manually. – Amin Negm-Awad Nov 07 '16 at 20:54
1

It makes perfect sense. The declaration of a property gives the user of the class information. An user of the class is allowed to expect from the – synthesized or manual – implementation, what you tell in the declaration. The user cannot even know, whether it is synthesized or not.

If you implement the getter (or whatever accessor) yourself, you should reflect the atomicity of your implementation in the declaration of the property. If you have a non-atomic implementation, you should add that to the declared property.

Amin Negm-Awad
  • 16,582
  • 3
  • 35
  • 50
  • hm also a very valid point. It's true. For public API point of view it makes totally sense to tell them about the atomicy – Buju Nov 08 '16 at 14:15
  • This makes no sense. The only problem with nonatomic writable properties is that they can return invalid values if they are being set while being read at the same time so don't ever do that! atomic will prevent that from happening, as you will either get the value prior to or after the set but never an invalid value in between. Yet caller of a readonly property can always expect to get valid return value, no matter if they are atomic or not. If your nonatomic readonly getter may return invalid values, your implementation is broken as how should a caller prevent that from happening then? – Mecki Mar 18 '21 at 01:48
  • In the first case you can argue that the caller was using your public API incorrectly. He was informed that the property is nonatomic, so he should not have tried to write the property on one thread while reading it on another one. Your implementation was correct but the caller used your public API incorrectly, the programming mistake is at the caller code. In the second case though, he cannot ever set the property, he can only read it and if that produces incorrect results, what did he do wrong? Nothing. So here the error would be at the called code, the caller made no mistake. – Mecki Mar 18 '21 at 01:52