2.7 KiB
The Elegant Design of NSRange
typedef struct _NSRange { NSUInteger location; NSUInteger length; } NSRange;
- Looking at the official documentation source, you can see NSRange is a struct. But if you were to design such a data type, how would you do it?
Design it as a struct, but what about some helper operations? For developer convenience, design a way for developers to quickly know the upper bound of this struct.
Apple was clever and designed an inline function:
NS_INLINE NSUInteger NSMaxRange(NSRange range) {
return (range.location + range.length);
}
- What is an inline function?
NS_INLINE return_type functionName(parameter_list) {
// function implementation
// return ;
}
- Applications of inline functions
For example, a custom alert:
NS_INLINE void tipWithMessage(NSString *message){
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:@"Tip" message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:nil, nil];
[alerView show];
[alerView performSelector:@selector(dismissWithClickedButtonIndex:animated:) withObject:@[@0, @1] afterDelay:0.9];
});
}
- Notes about inline functions
Inline functions save the overhead of a function call at the cost of code duplication. They reduce call overhead and thus can improve execution speed. If the time to execute the inline function's code is large compared to the function call overhead, the efficiency gain will be small.
Also, each call site of an inline function copies the function code, so the program size increases and consumes more text/code segment space. Therefore, the following situations are not suitable for inline functions:
* If the function body is relatively long, inlining will cause significant memory/code size increase.
* If the function body contains loops, the execution time of the function body will be larger than the call overhead.
- FOUNDATION_EXPORT
Looking at NSRange's code you may also notice the keyword FOUNDATION_EXPORT, which can be used to define constants.
FOUNDATION_EXPORT and #define can both be used to define constants. Usage:
// .h
FOUNDATION_EXPORT NSString *const NickName;
// .m
NSString *const NickName = @"Hangzhou Xiao Liu";
So how does it differ from #define?
FOUNDATION_EXPORT is more efficient when checking whether string values are equal. When using NickName == MyName to compare, FOUNDATION_EXPORT compares pointers, whereas with #define you would use [NickName isEqualToString:MyName] to compare contents.
* Essentially FOUNDATION_EXPORT compares pointers directly.
* \#define compares whether each string's content is equal.