13

What does the unavailable attribute in Objective C do?

__attribute__((unavailable("message")))

Is there any online reference to this and other attributes in Clang?

David Rönnqvist
  • 56,267
  • 18
  • 167
  • 205
cfischer
  • 24,452
  • 37
  • 131
  • 214

2 Answers2

15

The unavailable attribute marks a function declaration so that you can generate an error message if someone tries to use it. It's essentially the same as the deprecated attribute, except that trying to use a deprecated function just causes a warning, but using an unavailable one causes an error. Documentation at: http://clang.llvm.org/docs/LanguageExtensions.html

Here's a simple use case example. First the code:

void badFunction(void) __attribute__((unavailable("Don't use badFunction, it won't work.")));

int main(void)
{
    badFunction();
    return 0;
}

And then building it:

$ make example
cc     example.c   -o example
example.c:5:5: error: 'badFunction' is unavailable: Don't use badFunction, it
      won't work.
    badFunction();
    ^
example.c:1:6: note: function has been explicitly marked unavailable here
void badFunction(void) __attribute__((unavailable("Don't use...
     ^
1 error generated.
make: *** [example] Error 1
Carl Norum
  • 219,201
  • 40
  • 422
  • 469
  • I was planning to use it to make sure a method in an abstract class is never called. However, it generates an error even when subclasses send the message. :-( What's the intended usage of unavailable then? – cfischer Jun 23 '13 at 15:29
  • 1
    It's intended for obsolete API that you want/need to keep around in a header file for some reason but you don't actually have an implementation for. You might do so for the purpose of issuing a detailed message to the user about a particular function being missing in a new version of a library you distribute, for example. Your use case isn't something that `unavailable` was intended for. – Carl Norum Jun 23 '13 at 15:31
  • 1
    @urimoai Put the "private" API in a class extension declaration in `MyClass_Private.h` or `MyClass_Internal.h`. For a framework project, mark the role as `Private` or `Project` to control where the header file is installed. Otherwise, if you are producing a static library for others, only include `MyClass.h` in your distro. – bbum Jun 23 '13 at 17:33
4

Without getting into a discussion of the pros and cons of singleton objects, attribute((unavailable("message"))) is handy for preventing singletons from being instantiated outside of the standard "sharedInstance" method.
For instance, in the header file of your singleton manager object the following lines will prevent the use of alloc, init, new or copy.

// clue for improper use (produces compile time error)
+ (instancetype)alloc __attribute__((unavailable("alloc not available, call sharedInstance instead")));
- (instancetype)init __attribute__((unavailable("init not available, call sharedInstance instead")));
+ (instancetype)new __attribute__((unavailable("new not available, call sharedInstance instead")));
- (instancetype)copy __attribute__((unavailable("copy not available, call sharedInstance instead")));

In order to instantiate your singleton you will need to roll your own custom initialization routine. Something along the lines of:

@interface singletonManager ()
-(instancetype)initUniqueInstance;
@end

@implementation singletonManager

+ (instancetype)sharedInstance
{
    static id instance = nil;
    static dispatch_once_t onceToken = 0;
    dispatch_once(&once_token,^
    {
        instance = [[super alloc] initUniqueInstance];
    });
    return instance;
}

- (instancetype)initUniqueInstance
{
    if (( self = [super init] ))
    {
        //regular initialization stuff
    }
    return self;
}

@end
Tuique
  • 125
  • 4
  • How do you allow your private implementation to create an instance to be used as the singleton? – RyanM Mar 01 '16 at 22:15
  • @RyanM I added an example of a custom initializer that will get the job done without triggering the compiler error – Tuique Mar 03 '16 at 17:41