你見過哪些令你瞠目結舌的 Objective-C 代碼技巧?
看到程序員主題下面好幾個類似問題,竟然沒有iOS開發的,特此請教
用 Property() 這個 macro 在編譯時檢查一個 class 是否包含一個 property,並取到那個 property 的名字(一個 NSString),配合 Core Data 使用非常方便。
// NSObject+PropertyName.h
#define Property(Class, PropertyName) @(((void)(NO ((void)[Class nilObject].PropertyName, NO)), # PropertyName))
@interface NSObject (PropertyName)
+ (instancetype)nilObject;
@end
// NSObject+PropertyName.m
#import "NSObject+PropertyName.h"
@implementation NSObject (PGPropertyName)
+ (instancetype)nilObject
{
return nil;
}
@end
還有就是用 hack 的方式隱藏一個 class 真正的 superclass。
// Foo.h
@interface Foo : NSObject
- (void)foo;
@end
// Foo.m
#import "Boo.h"
@interface Foo : Boo
@end
@implementation Foo
- (void)foo
{
NSLog(@"Hello, world!");
}
@end
N年前第一次看到這段代碼的時候驚呆了= =
去掉UINavigationBar底部的分割線
//導航欄背景透明
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];//導航欄底部線清楚
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;self.navigationController.navigationBar.translucent = YES;[self.navigationController.navigationBar setShadowImage:[UIImage new]];加了沒有圖的圖上去。
這樣的話,可以直接讓navigationBar和下面的視圖渾然一體。Method Swizzle: Objective-C的hook方案(一): Method Swizzling
SEL originalSelector = @selector(viewWillAppear:);
SEL swizzledSelector = @selector(tracking_viewWillAppear:);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
WeakifySelf.h
#define weakifySelf(BLOCK...)
_Pragma("clang diagnostic push")
_Pragma("clang diagnostic ignored "-Wshadow"")
rs_blockWithWeakifiedSelf(self, ^id(__typeof(self) __weak self) {
return (BLOCK);
})
_Pragma("clang diagnostic pop")
#define strongify(VAR)
id _strong_##VAR = VAR;
__typeof(VAR) __strong VAR = _strong_##VAR;
#define strongifyAndReturnIfNil(VAR)
strongify(VAR)
if (!(VAR)){ return;}
id rs_blockWithWeakifiedSelf(id self, id(^intermediateBlock)(id __weak self));
#import "WeakifySelf.h"
id rs_blockWithWeakifiedSelf(id self, id(^intermediateBlock)(id __weak self)){
id __weak weakSelf = self;
return intermediateBlock(weakSelf);
}
- (void)someMethod {
self.block = weakifySelf(^{
// Self may be nil here
[self doSomeWork];
strongifyAndReturnIfNil(self);
// Self is strong and not nil.
// We can do ivars dereferencing
// and other stuff safely
self.XXX = XXX;
});
}
不如授人以漁?UI控制項上有任何費解搞不定的,或者想屏蔽哪些功能的,或要改一下顏色的 打開reveal(強烈推薦)或者Xcode 看看view hierarchy 用kvc或者runtime基本都能改method swizzling這種靠腦洞的就不說了(逃
關於weakify 和strongify的裝B寫法傳統寫法
#ifndef weakify
#if __has_feature(objc_arc)
#define weakify( x ) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored "-Wshadow"") \
autoreleasepool{} __weak __typeof__(x) __weak_##x##__ = x; \
_Pragma("clang diagnostic pop")
#else
#define weakify( x ) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored "-Wshadow"") \
autoreleasepool{} __block __typeof__(x) __block_##x##__ = x; \
_Pragma("clang diagnostic pop")
#endif
#endif
#ifndef strongify
#if __has_feature(objc_arc)
#define strongify( x ) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored "-Wshadow"") \
try{} @finally{} __typeof__(x) x = __weak_##x##__; \
_Pragma("clang diagnostic pop")
#else
#define strongify( x ) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored "-Wshadow"") \
try{} @finally{} __typeof__(x) x = __block_##x##__; \
_Pragma("clang diagnostic pop")
#endif
#endif
裝B寫法
#define weakify(...) \
autoreleasepool {} \
metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)
#define strongify(...) \
try {} @finally {} \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored "-Wshadow"") \
metamacro_foreach(rac_strongify_,, __VA_ARGS__) \
_Pragma("clang diagnostic pop")
利用runTime獲取私有屬性。
首先導入runtime
然後獲取一下UIButton的所有屬性,不管是暴露還是未暴露的。
這是printIvar的具體實現,核心就是利用runtime中的 class_copyIvarList這個方法。
===================以下是控制台列印的結果============================
1.Runtime2.OC中使用GCC語法
self.searchBar =
({
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:({
CGRect frame = self.tableView.frame;
frame.size.height = 50.0f;
frame;
})];
searchBar.delegate = self;
searchBar;
});3.帶提醒功能的宏,refer: https://github.com/jspahrsummers/libextobjc
#define keypath(OBJ, PATH)
(((void)(NO ((void)OBJ.PATH, NO)), # PATH))與其說令人瞠目結舌的編碼技巧,倒不如說有令人瞠目結舌的組織思路
我覺得一些複雜的邏輯卻用一些巧妙的設計簡單的實現了功能,而且很容易擴展,這個超牛逼!
推薦閱讀:
※APICloud是免費用的嗎?
※android v7包里的Toolbar,怎麼定製圖標、字體居中的效果?
※互聯網上的各種軟體是怎麼盈利的?
※我有一些想法,但不會開發APP,我希望有人可以開發一個APP,專門搜集一些別人的想法創意意見的APP,現實嗎?
TAG:程序員 | iOS開發 | iOSvsAndroid | 移動開發 |