Unlocking UIKIT_EXTERN: How Macros Shape iOS Compilation and Symbol Visibility
This article explores the purpose and implementation of UIKIT_EXTERN and related macros in iOS, explaining how they manage global constants, control symbol visibility across dynamic libraries, and provide practical examples of extern, static, and const usage for compilation optimization and conflict resolution.
Small Macro, Big World
Preface: describing the hardest technology in the simplest language.
本人是作者在对项目中的宏进行编译层面优化时有感而发的文章,如果有那些论述模糊或者不准确,请联系 [email protected]
Table of Contents
About UIKIT_EXTERN
UIKIT_EXTERN Code Walkthrough
Principle
Application Scenarios
Extensions
Reference Documents
Conclusion
About UIKIT_EXTERN
In development we often declare many global constants to ensure project‑wide availability. In iOS this is done with UIKIT_EXTERN, which guarantees global accessibility while preventing conflicts between dynamic libraries.
#ifdef __cplusplus
#define UIKIT_EXTERN extern "C" __attribute__((visibility ("default")))
#else
#define UIKIT_EXTERN extern __attribute__((visibility ("default")))
#endifMany frameworks such as YYKit also use this pattern.
#ifdef __cplusplus
#define YY_EXTERN_C_BEGIN extern "C" {
#define YY_EXTERN_C_END }
#else
#define YY_EXTERN_C_BEGIN
#define YY_EXTERN_C_END
#endifWhy write it this way? What effect does it have? Which scenarios apply? The article will reveal the answers.
UIKIT_EXTERN Code Walkthrough
Interpretation 1.0 eg
如果是C++语言
那么就声明此宏定义,在C++语言里面写C需要加上C的说明,设置编译器属性为 default,保证对外部的类可见
否则
就声明此宏定义,设置编译器属性为 default,保证对外部的类可见
在这里,宏仅仅是对象宏,等量替换,后者替换前者Principle
__attribute__is a compiler attribute used in GNU C to describe special properties such as visibility.
Visibility controls symbol export in dynamic libraries; default makes a symbol visible, hidden hides it.
Example compilation commands and readelf output illustrate how visibility affects symbol visibility.
test2.cc 可以调用func1,原因是test1.o和test2.o同属于一个so文件(so文件是Linux下的动态库文件,等同于iOS下的动态库UIKit等)
// test1.cc file
#include <stdio.h>
extern "C" void func1();
void func1() { printf("in %s
", __FUNCTION__); }
// compile with -fvisibility=hidden
__attribute__ ((visibility("hidden"))) void func1();
// test2.cc file
extern "C" void func1();
extern "C" void func2() { func1(); printf("in %s
", __FUNCTION__); }
// main.cc file
extern "C" void func1();
extern "C" void func2();
int main() { func1(); func2(); return 0; }
// compile result
g++ -c main.cc
g++ -fvisibility=hidden -fPIC -c test1.cc
g++ -fvisibility=hidden -fPIC -c test2.cc
g++ -shared -o libvisibility.so test1.o test2.o
g++ -o test main.o -lvisibility -L .Result: func1 has visibility set to hidden, while func2 is default, so func1 cannot be called from main() but func2 can.
Application Scenarios
Compilation optimization
Global variable declaration
Resolving conflicts between different libraries
Extensions
Macro
// concat two params
#define __SN_PASTE__(A,B) A##B
// main macro
#define SNSquare(A) __SNSQUARE_IMPL__(A,__COUNTER__)
// param counter
#define __SNSQUARE_IMPL__(A,L) ({ __typeof__(A) __SN_PASTE__(__a,L) = (A); (__SN_PASTE__(__a,L)) * (__SN_PASTE__(__a,L)); })
int res = SNSquare(3);
NSLog(@"3 square is %d",res);关于宏,喵神写了一篇非常好的文章,这里就不再赘述,链接见文章底部。
extern
extern declares a global variable without defining it.
// ViewController.h
#import "ViewController.h"
int x = 24;
@interface ViewController ()
@end
@implementation TestViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor purpleColor];
}
@end
// BViewController.m
#import "BViewController.h"
extern int x;
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"x is:%d",x); // x is 24
}
@endSearch flow: the compiler first looks in the current file; if not found, it searches other files.
static
static modifies variable scope and lifetime.
static int a = 3;
++a;
NSLog(@"a is %d",a); // a is 4Static variables persist for the entire program lifetime and exist only once.
const
const marks a variable as read‑only.
NSString * const kTableViewCell = @"kTableViewCell";In iOS, const variables improve pre‑compilation speed and enforce read‑only access.
iOS extern
extern can modify any variable type; multiple declarations, single definition.
// UIKIT_EXTERN example
UIKIT_EXTERN const CGFloat kAnimationInterval;
FOUNDATION_EXTERN NSString * const kAnimationKey;
// implementation
const CGFloat kAnimationInterval = 0.5f;
NSString * const kAnimationKey = @"kAnimationKey"; UIKIT_EXTERNis defined in UIKit/UIKitDefines.h; FOUNDATION_EXTERN is defined in Foundation/NSObjCRuntime.h.
Reference Documents
Macro black magic: https://onevcat.com/2014/01/black-magic-in-macro/
YYKit usage: https://github.com/ibireme/YYKit/blob/master/YYKit/Base/YYKitMacro.h
G++ variable attributes: https://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html
G++ function attributes: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
Conclusion
关于一个小小的宏字段,引发了很多的畅想,还有一些更高级的用法,感兴趣的作者可以搜索下ReactiveCocoa这个框架,作者把宏应用到出神入化的地步,简直🐂出天际!!!技术之路需要不断输入输出,我们都是平凡人,只不过看谁坚持的久而已。
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Sohu Smart Platform Tech Team
The Sohu News app's technical sharing hub, offering deep tech analyses, the latest industry news, and fun developer anecdotes. Follow us to discover the team's daily joys.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
