`
啸笑天
  • 浏览: 3462621 次
  • 性别: Icon_minigender_1
  • 来自: China
社区版块
存档分类
最新评论

__attribute__

    博客分类:
  • ios
 
阅读更多

https://blog.twitter.com/2014/attribute-directives-in-objective-c

http://nshipster.com/__attribute__/

http://blog.sunnyxx.com/2014/09/15/objc-attribute-cleanup/   黑魔法__attribute__((cleanup))

http://blog.csdn.net/bingwa/article/details/6338267  Objective-C 之 Attribute & Package

http://blog.csdn.net/ruixj/article/details/4274721  __attribute__ 详解

 

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

In this post, we’ll examine what __attribute__ directives are and how they can be used in development. The goal is to establish a value to using __attribute__ directives in any codebase and to provide a starting point with some directives that anyone can start using right away.

  1. What are __attribute__ directives?
  2. When should I use an __attribute__ directive?
  3. Recognizing the dangers of misusing an __attribute__ directive
  4. Core __attribute__ directives
  5. ARC __attribute__ directives
  6. More __attribute__ directives
  7. in, out and inout
  8. __attribute__ directives as a tool
  9. __attribute__ resources

What are __attribute__ directives?

The __attribute__ directive is used to decorate a code declaration in C, C++ and Objective-C programming languages. This gives the declared code additional attributes that would help the compiler incorporate optimizations or elicit useful warnings to the consumer of that code.

Better said, __attribute__ directives provide context. The value of providing context to code cannot be overstated. Developers have provided context by way of explicit declarations and comments since before the advent of the integrated circuit, but the value of providing context that can be evaluated by a compiler gives us a whole new level of control. By explicitly providing the confines of how an API behaves to the compiler, a programmer can gain some tangible benefits. The directives can be used to enforce compliance with how other programmers consume that API. In other cases, __attribute__ directives can help the compiler to optimize - sometimes to large performance gains.

As Mattt Thompson cogently put it in a blog post: “Context is king when it comes to compiler optimizations. By providing constraints on how to interpret your code, [you’ll increase] the chance that the generated code is as efficient as possible. Meet your compiler half-way, and you’ll always be rewarded… [It] isn’t just for the compiler either: The next person to see the code will appreciate the extra context, too. So go the extra mile for the benefit of your collaborator, successor, or just 2-years-from-now you.” Which leads nicely into wise words from Sir Paul McCartney, “and in the end, the love you take is equal to the love you make.”

When should I use an __attribute__ directive?
Whenever you have an opportunity to provide additional context to a code declaration (variable, argument, function, method, class, etc), you should. Providing context to code benefits both the compiler and the reader of the API, whether that’s another programmer or yourself at a future point in time.

Now let’s be practical for a moment too. There are dozens of __attribute__ directives and knowing every single one of them for every single compiler on every single architecture is just not a reasonable return on investment. Rather, let’s focus on a core set of commonly useful __attribute__ directives any developer can take advantage of.

Recognizing the dangers of misusing an __attribute__ directive
Just as poorly written comments and documentation can have consequences, providing the wrong __attribute__ can have consequences. In fact, since an __attribute__ affects code compilation, affixing the wrong __attribute__ to code can actually result in a bug that could be incredibly difficult to debug.

Let’s take a look at an example of where an __attribute__ directive can be misused. Let’s suppose I have an enum that I use pretty often and frequently want a string version for it, whether it’s for populating a JSON structure or just for logging. I create a simple function to help me convert that enum into an NSString.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Header declarations
 
typedef NS_ENUM(char, XPL802_11Protocol) {
    XPL802_11ProtocolA = 'a',
    XPL802_11ProtocolB = 'b',
    XPL802_11ProtocolG = 'g',
    XPL802_11ProtocolN = 'n'
};
 
FOUNDATION_EXPORT NSString *XPL802_11ProtocolToString(XPL802_11Protocol protocol);
 
// Implementation
 
NSString *XPL802_11ProtocolToString(XPL802_11Protocol protocol)
{
    switch(protocol) {
        case XPL802_11ProtocolA:
             return @"802.11a";
        case XPL802_11ProtocolB:
             return @"802.11b";
        case XPL802_11ProtocolG:
             return @"802.11g";
        case XPL802_11ProtocolN:
             return @"802.11n";
        default:
           break;
    }
    return nil;
}

So I have my great little converting function and I end up using it a lot in my code. I notice that my return values are constant NSString references and are always the same based on the protocol that is provided as a parameter to my function. Aha! A prime candidate for a const __attribute__ directive. So I just update my header’s function declaration like so:

1
FOUNDATION_EXPORT NSString*XPL802_11ProtocolToString(XPL802_11Protocol protocol)__attribute__((const));

And voilà! I have just provided context to any consumer of this function such that they know that the return value is completely based on the provided parameter and won’t change over the course of the process’ life. This change would also provide a performance boost, depending on how often the function is called, since the compiler now knows that it doesn’t actually have to re-execute this function if it already has cached the return value.

Now, let’s say one day I notice the enum value is the character of the protocol and I decide to be clever and change my implementation to something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
NSString *XPL802_11ProtocolToString(XPL802_11Protocol protocol)
{
switch(protocol) {
    case XPL802_11ProtocolA:
    case XPL802_11ProtocolB:
    case XPL802_11ProtocolG:
    case XPL802_11ProtocolN:
       return [NSString stringWithFormat:@"802.11%c", protocol];
    default:
       break;
  }
      return nil;
}

Now since I failed to remove the const attribute, I have just introduced a massive bug that could easily crash my app. Why? Well, the key difference is that the return value of my function is no longer a constant reference. When we were returning hard coded strings before, the compiler stored those strings as persistent memory and those NSStrings effectively had a retain count of infinite. Now that we dynamically generate the string based on the protocol’s char value, we are creating a new string every time - and that means memory that changes. The reference returned in one call to the function won’t actually be the same reference as a subsequent identical call. The problem will rear it’s head when the compiler optimizes subsequent calls to that function to just immediately access what the compiler considers the known return value, which would be the reference returned by the original call. Sadly, that reference has likely been deallocated and potentially reallocated by some other memory allocation by now. This will lead to our application crashing on either a bad memory access or an invalid method call on the object that occupies that reference’s memory. The worst of this is that the optimization that would cause this crash will only happen in builds that are highly optimized. Since debug builds often have optimizations turned down, you can run your app in a debugger forever and never reproduce it, making this bug, like most __attribute__ based bugs, very hard to figure out and fix.

This is bug effectively boils down to treating a function that returns transient memory as const. The same goes for functions or methods that take transient memory as a parameter. Easy enough to remember is that any function returning a pointer return value must return a constant reference to use the const __attribute__ directive and absolutely no const function can have a pointer (including an Objective-C object) as a parameter.

Now this example is merely a precaution for using __attribute__ directives and shouldn’t deter you from using them in your code. If you stick to __attribute__ directives you understand and pay attention to how they are used, you’ll be able to steer clear of these bugs and harness the power __attribute__ directives were meant to provide. Just remember, when in doubt, don’t attribute, because providing the wrong context is worse than providing no context.

To point you in the right direction, below is a compiled list of useful attributes that should be more than enough to improve any developer’s tool belt.

Core __attribute__ directives
__attribute__((availability(…))), NS_AVAILABLE and NS_DEPRECATED

Indicate the availability of an API on the platform

NS_AVAILABLE: Apple macro for attributing an API as available in a given OS release. NS_AVAILABLE_IOS(available_os_version)

NS_DEPRECATED: Apple macro for attributing an API as deprecated in a given OS release.

NS_DEPRECATED_IOS(available_os_version,deprecated_os_version)

  • Use NS_AVAILABLE and NS_DEPRECATED macros to hide the complexity of this attribute.
  • Commonly used when deprecating one API and adding a new API as a replacement.
  • When creating a new API for backwards compatibility, immediately attribute the API as deprecated and include a comment on the API that should be used for current OS targets.
  • These directives are tied to the operating system version and cannot be used for framework versioning. For those instances, use __attribute__((deprecated(…)).
1
2
3
4
5
6
7
8
9
FOUNDATION_EXPORT NSString * const MyClassNotification NS_AVAILABLE_IOS(3_0);
FOUNDATION_EXPORT NSString * const MyClassNotificationOldKey NS_DEPRECATED_IOS(3_0, 7_0);
FOUNDATION_EXPORT NSString * const MyClassNotificaitonNewKey NS_AVAILABLE_IOS(7_0);
 
NS_AVAILABLE_IOS(3_0)
<a href="https://twitter.com/intent/user?screen_name=class">@class</a> MyClass : NSObject
- (void)oldMethod NS_DEPRECATED_IOS(3_0, 6_0);
- (void)newMethod:(out NSError * __autoreleasing *)outError NS_AVAILABLE_IOS(6_0);

__attribute__((deprecated(…))) and __attribute__((unavailable(…)))
Indicates that an API is deprecated/unavailable.

__attribute__((deprecated(optional_message)))
__attribute__((unavailable(optional_message)))

In case you don’t want to use the availability attribute for deprecation.

1
2
3
4
5
- (void)deprecatedMethod __attribute__((deprecated));
- (void)deprecatedMethodWithMessage __attribute__((deprecated("this method was deprecated in MyApp.app version 5.0.2, use newMethod instead"));
 
- (void)unavailableMethod __attribute__((unavailable));
- (void)unavailableMethodWithMessage __attribute__((unavailable("this method was removed from MyApp.app version 5.3.0, use newMethod instead"));

__attribute__((format(…))) and NS_FORMAT_FUNCTION

Indicates that a function/method contains a format string with format arguments.

__attribute__((format(format_type, format_string_index, first_format_argument_index)))
format_type: one of printf, scant, strftime, strfmon or __NSString__

Reminder: argument indexes when specified in an attribute are 1 based. When it comes to Objective-C methods, remember they are just C functions whose first 2 arguments are the id self argument and the SEL _cmd argument.

  • NS_FORMAT_FUNCTION: macro provided by Apple for __NSString__ type format string
  • Use NS_FORMAT_FUNCTION macro when attributing a method/function with an objective-c string for formatting.
1
2
3
4
FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
void MyLog(MyLogLevel lvl, const char *format, ...) __attribute((format(printf, 2, 3)));
// ...
- (void)appendFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(3, 4);

__attribute__((sentinel(…))) and NS_REQUIRES_NIL_TERMINATION

Indicates that a function/method requires a nil (NULL) argument, usually used as a delimiter. You can only use this attribute with variadic functions/methods.

__attribute__((sentinel(index))

index: the index offset from the last argument in the variadic list of arguments.

__attribute__((sentinel)) is equivalent to __attribute__((sentinel(0)))

You’ll almost always want to use the NS_REQUIRES_NIL_TERMINATION macro

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Example 1
- (instancetype)arrayWithObjects:... NS_REQUIRES_NIL_TERMINATION;
  
// Example 2 - of course you'd never do this...
NSArray *CreateArrayWithObjectsWithLastArgumentIndicatingIfArrayIsMutable(...) __attribute__((sentinel(1)));
  
void foo(id object1, id object2)
{
    NSArray *weirdArray = CreateArrayWithObjectsWithLastArgumentIndicatingIfArrayIsMutable(object1, object2, nil, YES);
    NSAssert([weirdArrayrespondsToSelector:<a href="https://twitter.com/intent/user?screen_name=selector">@selector</a>(addObject:)]);
    // ...
}

__attribute__((const)) and __attribute__((pure))
__attribute__((const)) is used to indicate that the function/method results are entirely dependent on the provided arguments and the function/method does not mutate state.
__attribute__((pure)) is almost the same as its const counterpart, except that the function/method can also take global/static variables into account.

  • Though adding the const or pure attribute to an Objective-C method is not as useful to the compiler due to the dynamic runtime, it is still VERY useful to a programmer reading an interface.
  • It is recommended that all singleton instance accessors use the const attribute.
  • The optimization upside of accurately using this attribute can be an enormous win. If you have an Objective-C class method that is frequently used and is const or pure, consider converting it into a C function to reap some serious benefits.
  • On the flipside, using this attribute incorrectly can lead to a nearly impossible to locate bug as actually seeing the redundant use of the function removed by the compiler requires looking at the assembly! Oh, and this type of bug will rarely show in a debug build since only highly optimized builds will have the bug.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Example 1: Singleton
 
<a href="https://twitter.com/intent/user?screen_name=interface">@interface</a> MySingleton : NSObject
+ (MySingleton *)sharedInstance __attribute__((const));
 
// Example 2: Function overhead optimization
 
// Get the description of a specified error number
const char *StringForErrNo(int errorNumber) __attribute__((const));// strerror(errorNumber)
 
// Get the description of the global errno error number
const char *StringForGlobalErrNo(void) __attribute__((pure)); // strerror(errno)
 
void DoStuffWithGlobalErrNo()
{
      NSLog(@"%@ %s", [NSStringstringWithUTF8String:StringForGlobalErrNo()],StringForGlobalErrNo());
      printf("%s\n", StringForGlobalErrNo());
      printf("%i\n", strlen(StringForGlobalErrNo()));
}
 
// will compile as something more like this:
 
void DoStuffWithGlobalErrNo()
{
const char *__error = StringForGlobalErrNo();
NSLog(@"%@ %s", [NSString stringWithUTF8String:__error], __error);
     printf("%s\n", __error);
     printf("%i\n", strlen(__error));
}
 
// which effectively eliminates both 1) the overhead of the function call and 2) the internal execution cost of the function
 
// Example 3: Function execution cost optimization
 
int nthFibonacci(int n) __attribute__((const)); // naive implementation to get the nth fibonacci number without any caching
 
void TestFibonacci()
{
     time_t start = time(NULL);
     int result1 = nthFibonacci(1000); // execution time of D
     time_t dur1 = time(NULL) - start; // some large duration D
     int result2 = nthFibonacci(1000); // execution time of 1
     time_t dur2 = time(NULL) - start; // same as dur1, duration D
     int result3 = nthFibonacci(999); // execution time of ~D
     time_t dur3 = time(NULL) - start; // duration of 2*D
 
// The __attribute__((const)) directive can effectively eliminate a redundant call to an expensive operation...nice!
}

 

__attribute__((objc_requires_super)) and NS_REQUIRES_SUPER
Indicate that the decorated method must call the super version of it’s implementation if overridden.

  • Existed in LLVM for Xcode 4.5 but had bugs and wasn’t exposed with NS_REQUIRES_SUPER until Xcode 5.0
  • When creating a class that is expressly purposed to be a base class that is subclassed, any method that is supposed to be overridden but needs to have the super implementation called needs to use this macro.
  • This attribute can be a large codebase win by contextualizing what methods are necessary for a base class to work. Widely adopt this attribute and your codebase will benefit.
1
2
3
4
5
6
7
8
9
10
11
12
<a href="https://twitter.com/intent/user?screen_name=interface">@interface</a> MyBaseClass : NSObject
- (void)handleStateTransition NS_REQUIRES_SUPER;
 
// ...
 
<a href="https://twitter.com/intent/user?screen_name=interface">@interface</a> MyConcreteClass : MyBaseClass
 
- (void)handleStateTransition
{
     [super handleStateTransition]; // @end

 

ARC __attribute__ directives
__attribute__((objc_precise_lifetime)) and NS_VALID_UNTIL_END_OF_SCOPE

Indicate that the given variable should be considered valid for the duration of its scope

  • Though this will rarely come up, it can be a big help combatting a brain scratching crash that only appears in release builds (since the optimization likely doesn’t happen in your debug build)
1
2
3
4
5
6
7
8
9
10
11
12
- (void)foo
{
    NS_VALID_UNTIL_END_OF_SCOPE MyObject *obj = [[MyObject alloc] init];
    NSValue *value = [NSValue valueWithPointer:obj];
 
// do stuff
 
    MyObject *objAgain = [value pointerValue];
    NSLog(@"%@", objAgain);
}
 
/* in ARC, without NS_VALID_UNTIL_END_OF_SCOPE, the compiler will optimize and after the obj pointer is used to create the NSValue the compiler will have no knowledge of the encapsulated use of the object in the NSValue. ARC will release obj and this NSLog line will crash with EXEC_BAD_ACCESS because the reference retrieved from the NSValue and stored in objAgain will now be pointing to the deallocated reference. */

__attribute__((ns_returns_retained)) and NS_RETURNS_RETAINED
Indicates to ARC that the method returns a +1 retain count.
Per Apple: only use this attribute for extraneous circumstances. Use the Objective-C naming convention of prefixing your method with alloc, new, copy, or mutableCopy to achieve the same result without an attribute.

  • ARC will follow a naming convention and this directive for how to manage the returned value’s retain count. If the implementation is non-ARC, it is up to the implementation to adhere to the rule such that when an ARC file consumes the API the contract is adhered to.
  • Honestly, you should just use the Apple recommend method prefix for methods and reserve this only for cases where you create an object with a +1 retain count with a function.
1
NSString *CreateNewStringWithFormat(NSString *format, ...)NS_FORMAT_FUNCTION(1, 2) NS_RETURNS_RETAINED;

__attribute__((ns_returns_not_retained)) and NS_RETURNS_NOT_RETAINED

Indicates to ARC that the method returns a +0 retain count. Default behavior of all methods and functions in Objective-C.
Per Apple: only use this attribute for extraneous circumstances. Use the Objective-C naming convention of NOT prefixing your method with alloc, new, copy, or mutableCopy to achieve the same result without an attribute.

  • ARC will follow a naming convention and this directive for how to manage the returned value’s retain count. If the implementation is non-ARC, it is up to the implementation to adhere to the rule such that when an ARC file consumes the API the contract is adhered to.
  • The only use for this attribute would be if you prefixed a method with alloc, new, copy, or mutableCopy but you didn’t want a +1 retain count - which is just nonsense. You should never need to use this attribute as it is implied on any method that doesn’t have a +1 keyword prefix.
1
- (NSString *)newUnretainedStringWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(3, 4) NS_RETURNS_NOT_RETAINED;

 

__attribute__((objc_returns_inner_pointer)) and NS_RETURNS_INNER_POINTER
Indicates that the method will return a pointer that is only valid for the lifetime of the owner. This will prevent ARC from preemptively releasing an object when the internal pointer is still in use.

  • This is actually a very important attribute that few developers do a very good job of using, but really should. If a method returns a non Objective-C reference, then ARC doesn’t know that the returned value is a reference that belongs to the owning object and will go away if the owning object goes away. Without this attribute, after the final use of an object ARC will release it. This can result in a crash if the inner pointer is referenced after the last use of the object since it could have been deallocated. Ordering lines of code is not enough either, since the compiler could easily reorder the execution order as a way to optimize.
1
2
3
4
5
6
7
8
9
10
11
12
13
<a href="https://twitter.com/intent/user?screen_name=interface">@interface</a> NSMutableData : NSData
- (void *)mutableBytes NS_RETURNS_INNER_POINTER;
 
 
void Foo(void)
{
     NSMutableData *buffer = [[NSMutableData alloc] initWithLength:8];
     char* cBuffer = buffer.mutableBytes;
     memcpy(cBuffer, "1234567", 8); // crash if NS_RETURNS_INNER_POINTER doesn't decorate the mutableBytes method
     printf("%s\n", cBuffer);
     (void)buffer; // this will not save us from a crash if the mutableBytes method isn't decorated with an NS_RETURNS_INNER_POINTER
}

 

__attribute__((ns_consumes_self)) and NS_REPLACES_RECEIVER
Indicates that the provided method can replace the receiver with a different object.
Presumes a +0 retain count (which can be overridden with NS_RETURNS_RETAINED, but if you do that you really need to be asking yourself “what the heck am I doing?”).

  • By default, all methods prefixed with init are treated as if this attribute were decorating them.
  • ARC makes this behavior really easy to implement. non-ARC implementers of the same behavior still need the decoration but also have to pay closer attention to how they are managing memory in the implementation. (awakeAfterUsingCoder: is regular source of memory leaks in non-ARC code bases)
1
2
3
<a href="https://twitter.com/intent/user?screen_name=interface">@interface</a> NSObject (NSCoderMethods)
- (id)awakeAfterUsingCoder:(NSCoder *) NS_REPLACES_RECEIVER;

 

__attribute__((objc_arc_weak_reference_unavailable)) and NS_AUTOMATED_REFCOUNT_WEAK_UNAVAILABLE
Indicates that the decorated class does not support weak referencing

  • Mac OS X Examples: NSATSTypesetter, NSColorSpace, NSFont, NSMenuView, NSParagraphStyle, NSSimpleHorizontalTypesetter, NSTextView,NSFontManager, NSFontPanel, NSImage, NSTableCellView, NSViewController, NSWindow, and NSWindowController.
  • iOS and Mac OS X Examples: NSHashTable, NSMapTable, or NSPointerArray
1
2
3
4
NS_AUTOMATED_REFCOUNT_WEAK_UNAVAILABLE
<a href="https://twitter.com/intent/user?screen_name=interface">@interface</a> NSHashTable : NSObject *Protocols*/>
//...

 

NS_AUTOMATED_REFCOUNT_UNAVAILABLE
Indicates that the decorated API is unavailable in ARC.

  • Can also use OBJC_ARC_UNAVAILABLE
1
- (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;

More __attribute__ directives
__attribute__((objc_root_class)) and NS_ROOT_CLASS
__attribute__((constructor(…))) and __attribute__((destructor(…)))
__attribute__((format_arg(…))) and NS_FORMAT_ARGUMENT
__attribute__((nonnull(…)))
__attribute__((returns_nonnull))
__attribute__((noreturn))
__attribute__((used))
__attribute__((unused))
__attribute__((warn_unused_result))
__attribute__((error(…))) and __attribute__((warning(…)))

in, out and inout

While we’re on the topic of providing context to code we should take the briefest of moments to bring up the Objective-C keywords in, out and inout. These little keywords are used to attribute Objective-C method arguments to provide context on whether the parameter is for input, output or both. These keywords came about with distributed objects along with oneway, byref, and bycopy but, in the spirit of providing context to programmers, these keywords can bridge the gap between the consumer of an API presuming how an argument will behave and knowing how that argument will behave. Consider using inout or out the next time you return a value via an argument and consumers of your API will appreciate it.

in
Indicates that the given argument is used only for input. This is the default behavior for non-pointers and Objective-C objects.

  • Use this keyword for methods that accept a pointer to a primitive that is read but never modified. Not a common case.
1
2
3
4
5
6
7
- (void)configureWithRect:(in CGRect *rect)
{
    if (rect) {
        _configRect = *rect;
    }
    [self _innerConfigure];
}

out
Indicates that the given argument is used just for output. This is never a default behavior.

  • This keyword doesn’t make sense to apply to non pointers, which are always in arguments.
  • Use this keyword for methods that return a value via an argument but don’t read that argument.
1
2
3
4
5
6
7
- (void)configure:(out NSError **error)
{
     NSError *theError = [self _configure];
     if (error) {
        *error = theError;
     }
}

 

inout
Indicates that the given argument is used for both input and output. This is the default behavior for pointers, except for Objective-C objects (which default to in).

  • This keyword doesn’t make sense to be applied to non pointers, which are always in arguments.
  • Use this to provide context when it may not be apparent how the pointer behaves.
  • Always use this to provide context when a method has numerous pointer arguments and at least one is in or out. Basically, when there are multiple pointer arguments and they are not all inout, every pointer argument should specify its behavior.
1
2
3
4
5
6
7
8
- (void)configureRect:(inout CGRect *rect)
{
     if (rect) {
         if (CGRectIsNull(*rect)) { // where rect acts an "in" argument
             *rect = CGRectMake(_x, _y, _w, _h); // where rect acts as an "out" argument
          }
      }
}

 

__attribute__ directives as a tool
With such a valuable tool available to the C languages, any team can benefit by using these __attribute__ directives to give context in their code. At Twitter, with a very large code base and many engineers developing on it daily, every bit of context that can be provided helps in maintaining a quality code base for reuse. Adding __attribute__ directives to your toolbelt of code comments and good naming conventions will give you a robust toolset for providing indispensable context to your code base. Don’t shy away from adding __attribute__ directives to your next project. Use them, evangelize them and everyone will benefit.

__attribute__ resources
GCC __attribute__ documentation
Clang __attribute__ reference
Clang Objective-C ARC Attributes
NSHipster’s __attribute__ blog post

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

黑魔法__attribute__((cleanup))

编译器属性__attribute__用于向编译器描述特殊的标识、检查或优化,几个常用的用法看《mattt大神的文章》就好。今天发现一个名为cleanup的黑魔法属性,简单介绍下。


基本用法

__attribute__((cleanup(...))),用于修饰一个变量,在它的作用域结束时可以自动执行一个指定的方法,如:

1
2
3
4
5
6
7
8
9
// 指定一个cleanup方法,注意入参是所修饰变量的地址,类型要一样
// 对于指向objc对象的指针(id *),如果不强制声明__strong默认是__autoreleasing,造成类型不匹配
static void stringCleanUp(__strong NSString **string) {
    NSLog(@"%@", *string);
}
// 在某个方法中:
{
    __strong NSString *string __attribute__((cleanup(stringCleanUp))) = @"sunnyxx";
} // 当运行到这个作用域结束时,自动调用stringCleanUp

所谓作用域结束,包括大括号结束、return、goto、break、exception等各种情况。
当然,可以修饰的变量不止NSString,自定义Class基本类型都是可以的:

1
2
3
4
5
6
7
8
9
10
// 自定义的Class
static void sarkCleanUp(__strong Sark **sark) {
    NSLog(@"%@", *sark);
}
__strong Sark *sark __attribute__((cleanup(sarkCleanUp))) = [Sark new];
// 基本类型
static void intCleanUp(NSInteger *integer) {
    NSLog(@"%d", *integer);
}
NSInteger integer __attribute__((cleanup(intCleanUp))) = 1;

假如一个作用域内有若干个cleanup的变量,他们的调用顺序是先入后出的栈式顺序;
而且,cleanup是先于这个对象的dealloc调用的。

进阶用法

既然__attribute__((cleanup(...)))可以用来修饰变量,block当然也是其中之一,写一个block的cleanup函数非常有趣:

1
2
3
4
// void(^block)(void)的指针是void(^*block)(void)
static void blockCleanUp(__strong void(^*block)(void)) {
    (*block)();
}

于是在一个作用域里声明一个block:

1
2
3
4
5
6
{
   // 加了个`unused`的attribute用来消除`unused variable`的warning
    __strong void(^block)(void) __attribute__((cleanup(blockCleanUp), unused)) = ^{
        NSLog(@"I'm dying...");
    };
} // 这里输出"I'm dying..."

这里不得不提万能的Reactive Cocoa中神奇的@onExit方法,其实正是上面的写法,简单定义个宏:

1
2
#define onExit\
    __strong void(^block)(void) __attribute__((cleanup(blockCleanUp), unused)) = ^

用这个宏就能将一段写在前面的代码最后执行:

1
2
3
4
5
{
    onExit {
        NSLog(@"yo");
    };
} // Log "yo"

这样的写法可以将成对出现的代码写在一起,比如说一个lock:

1
2
3
4
5
6
NSRecursiveLock *aLock = [[NSRecursiveLock alloc] init];
[aLock lock];
// 这里
//     有
//        100多万行
[aLock unlock]; // 看到这儿的时候早忘了和哪个lock对应着了

用了onExit之后,代码更集中了:

1
2
3
4
5
6
7
8
NSRecursiveLock *aLock = [[NSRecursiveLock alloc] init];
[aLock lock];
onExit {
    [aLock unlock]; // 妈妈再也不用担心我忘写后半段了
};
// 这里
//    爱多少行
//           就多少行

还是那句老话:剩下的就全靠想象力了。

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

常用:

__attribute__ ((warn_unused_result))的含义

如果某个函数使用了这个关键字,那么函数在被调用的时候,要检查或者使用返回值,某则编译器会进行警告。

使用场合:在把一些功能封装起来(或者SDK的编写)时候,如果对返回值的使用比较重要,那么使用这个关键字提醒编译器要检查返回值是否被利用。

举例:

-(BOOL)TestFunc:(NSInteger) num __attribute__ ((warn_unused_result))

{

    return num > 0?YES:NO;

}

如果我这么调用

    [self TestFunc:10];

 

@property(nonatomic, readonly, weak) UIView *mediatedAdView

 

    __attribute__((deprecated("Use adNetworkClassName.")));

@property(nonatomic, copy) NSDictionary *additionalParameters __attribute__((

 

    deprecated(" use registerAdNetworkExtras: and pass an instance of GADAdMobExtras.")));

 

- (id)init __attribute__((unavailable));

__attribute__((objc_requires_super))//子类必须调用super

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

分享到:
评论

相关推荐

    __attribute__ - NSHipster.pdf

    __attribute__ 编译器指令 __attribute__ 是一种编译器指令,用于指定声明的特性,从而实现更多的错误检查和高级优化。该指令的语法是 __attribute__ 后跟着两个括号(双括号使得宏定义变得容易,特别是在多个属性...

    GCC的__attribute__扩展功能

    GCC 的__attribute__扩展功能 本文将详细介绍 GCC 的__attribute__扩展功能,__attribute__是 GNU C 的一大特色,它可以设置函数属性、变量属性和类型属性。__attribute__书写特征是:__attribute__前后都有两个...

    attribute_用法_section_部分.doc

    attribute_用法_section_部分.doc

    GNU_CC中的attribute

    GNU CC 是一种基于 GCC(GNU Compiler Collection)的C编译器,它提供了许多扩展功能,其中一个重要的特性就是__attribute__机制。__attribute__允许程序员在声明函数、变量或类型时添加额外的元数据,以便让编译器...

    attribute详细介绍

    在Linux开发及GCC(GNU Compiler Collection)的使用过程中,深入理解`__attribute__`是至关重要的。`__attribute__`是GCC提供的一种特性,用于向编译器传递额外的信息,帮助优化代码、减少错误并提高程序的可读性和...

    keil中,RTT 实现代码放到 vector和code 放到ram

    4. **代码放到RAM**:对于需要在RAM中运行的代码,可以使用`__attribute__((section(".my_ram_code")))`这样的语法将函数声明为特定的RAM段。然后,在链接脚本中定义这个段,并映射到RAM区域。 5. **编译和链接**:...

    mdk_armcc_user_guide.pdf

    文档强调了__attribute__高级用法,这是一类指示编译器优化和行为的指令,通常用于嵌入式系统编程。由于文档内容较为丰富,以下将详细说明相关知识点。 首先,我们要明确__attribute__在编程中的用途。__attribute_...

    product_attribute_grid_1-1-1.zip

    此时,"product_attribute_grid_1-1-1.zip" 插件应运而生,它是一个专门针对Zencart设计的多属性零售批发插件,极大地提升了商品管理和销售效率。 此插件的核心功能是提供了一个属性网格系统,使商家能够更直观、更...

    Stm32 Section

    STM32,全称为STMicroelectronics Microcontroller,是意法半导体公司推出的基于ARM Cortex-M内核的微控制器系列。在嵌入式系统开发中,STM32因其高性能、低功耗以及丰富的外设接口而被广泛应用。...

    Magento 1.8版本下eav模型demo

    此代码仅供参考没有后台管理表格1.8版本下可用 ...2.eav_attribute,eav_attribute_group,eav_attribute_set,eav_entity_attribute,eav_entity_type 每个表多一条数据。 作者网站:http://www.sharpmagento.com/

    stock_by_attribute_1.5.3.zip

    zencart stock_by_attribute_1.5.3按属性购买,球衣电商网站常用的。This add-on is based on a Zen Cart contribution by dafonz (products_with_attributes_stock), which was adapted by danielcor for Zen Cart ...

    C++与操作系统等面试题64

    编写一个函数,在`main`函数执行之前先运行,并且利用`__attribute__((constructor))`和`__attribute__((destructor))`来指定函数的执行时机。此外,题目还提到了几种其他实现方法,包括利用全局静态变量初始化和...

    AttributeQuery.rar_AttributeQuery_arcgis

    本资源"AttributeQuery.rar_AttributeQuery_arcgis"提供了一种实现这一功能的方法,包括点选、框选以及高亮显示等多种交互方式,以增强用户对数据的理解和分析。 点选是GIS中常用的一种选择方法,用户可以通过点击...

    对于图像属性数据集的分类(SVM,MLP)_Attribute_classfication.zip

    对于图像属性数据集的分类(SVM,MLP)_Attribute_classfication

    rsl.rar_RSL Matlab_attribute reduction_rsl

    在标签中,“rsl__matlab”表明这是RSL算法与MATLAB的结合应用,“attribute_reduction”进一步确认了这是关于特征选择的讨论,“rsl”再次强调了与RSL方法的相关性。压缩包中的唯一文件名“rsl”可能是代码库的主...

    红帽子的一些库函数i386-redhat-linux.tar.gz

    红帽子的一些库函数i386-redhat-linux.tar.gz,在些版本没有这些库函数的,解压放在/usr/lib即可。因为geekos实验要用到。

    GNU_C语言语法_扩展

    2. **声明中的类型注解 (Type Attributes)**:GNU C允许在声明中添加类型属性,如`__attribute__((aligned))`用于指定对齐要求,`__attribute__((malloc))`用于表示函数返回的新分配内存,还有`__attribute__((no...

    gcc 函数属性 attribute ((constructor))使用demo

    demo演示了gpio_init(void) 和 key_init(void)如何设置__attribute__ ((constructor)) 属性,同时演示了添加key.c文件的不需要修改main.c的方法,此方法能减少对main.c的修改,也体现了软件设计--高内聚低耦合的思想...

    Python库 | easy_module_attribute_getter-0.9.13-py3-none-any.whl

    资源分类:Python库 所属语言:Python 资源全名:easy_module_attribute_getter-0.9.13-py3-none-any.whl 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059

Global site tag (gtag.js) - Google Analytics