1、使用函数指针调用OC函数
-(void)performSelector
{
SEL selector = @selector(printImp);
IMP imp = [self methodForSelector:selector];
((void(*)(id,SEL))imp)(self,selector);
}
-(void)printImp
{
NSLog(@"MemoryCollectPerformance Print.....");
}
2、了解API以下的东西的话,依然可以利用Obj-C的runtime。 可以在这里看到
http://opensource.apple.com/source/objc4/objc4-493.11/runtime/ ,尤其是objc-runtime.m, 这里提供了很多学习用的"工具"。比如经典的method_exchangeImplementations(),您可以用它研究很多黑箱过程的来龙去脉。值得一提的是, 这种技巧(method swizzling)是合法的,可以在App Store 中使用! 苹果曾给使用了相关技巧的开发者发过邮件,表示出于安全性和稳定性最好不再使用, 但没有禁止。
3、界面布局
// 1、AutoLayout 手写
UIEdgeInsets padding = UIEdgeInsetsMake(0, 0, 10, 10);
self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addConstraints:@[
[NSLayoutConstraint constraintWithItem:self.tableView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:padding.top],
[NSLayoutConstraint constraintWithItem:self.tableView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:padding.left],
[NSLayoutConstraint constraintWithItem:self.tableView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:-padding.right],
[NSLayoutConstraint constraintWithItem:self.tableView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-padding.bottom]]];
// 2、VFL
NSDictionary* views = NSDictionaryOfVariableBindings(_tableView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[_tableView]-30-|" options:NSLayoutFormatAlignAllTop | NSLayoutAttributeBottom metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[_tableView]-30-|" options:NSLayoutFormatAlignAllLeft | NSLayoutAttributeRight metrics:nil views:views]];
// 3、Masonry
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.view);
make.size.mas_equalTo(CGSizeMake(300, 200));
}];
//4、aotulayout(Xib)
3、定时器避免循环引用,不释放问题:
Timer持有Target, runloop持有 timer,如果不调用 invalidate 那么timer不会被ruloop释放
3.1、分类实现创建NStimer分类:
+ (NSTimer *)apm_scheduledTimerWithTimeInterval:(NSTimeInterval)ti userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo callback:(void (^)(void))block{
return [self scheduledTimerWithTimeInterval:ti target:self selector:@selector(action:) userInfo:[block copy] repeats:yesOrNo];
}
+ (void)action:(NSTimer*)userInfo{
void (^block)(void) = userInfo.userInfo;
if (block) {
block();
}
}
3.2、创建一个类,让这个类弱引用target,同时实现TimerProtocol协议,具体使用定时器类也需要实现TimerProtocol协议:
@protocol TimerProtocol <NSObject>
- (void)timerInvoke;
@end
@interface TimeProxy : NSObject<TimerProtocol>
@property (nonatomic,weak) id<TimerProtocol> target;
@end
@implementation TimeProxy
- (void)timerInvoke{
if([self.target respondsToSelector:@selector(timerInvoke)]){
[self.target performSelector:@selector(timerInvoke)];
}
}
@end
//具体引用定时器的实现类实现TimerProtocol协议,实现timerInvoke方法
TimeProxy* proxy = [TimeProxy new];
proxy.target = self;
self.timer = [NSTimer timerWithTimeInterval:1.0 target:proxy selector:@selector(timerInvoke) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
3.3、交给NSProxy子类NSTimerProxy去实现:
//这个是NSProxy的子类NSTimerProxy,_target就是实现能够响应定时器的selector
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [_target methodSignatureForSelector:selector];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation invokeWithTarget:_target];
}
//具体实现逻辑:
NSTimerProxy* proxy = [NSTimerProxy proxyWithTarget:self];
self.timer = [NSTimer timerWithTimeInterval:1.0 target:proxy selector:@selector(timerInvoke) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
4、
Javascript和OC调用:
4.1、在同一个JSContext环境下声明 JSContext* context = [[JSContext alloc] init];
context["add"] = ^(int a, int b){
NSLog(@"add:a+b = %d",a+b);
};
4.1.1、[context evaluateScript:@"add(50,50)"];
4.1.2、在js中调用add(50,50) 如:JSPatch就这样实现。需要[context evaluateScript:xxx.js] 才可以调用js中的function
4.2、WKWebview和UIWebview(这里是WKWebview)
4.2.1、实现WKScriptMessageHandler协议,注册[config.userContentController addScriptMessageHandler:self name:NSStringFromSelector(@selector(playSound))];
4.2.2、js使用
var messageToPost = {'key':'value','key2':'value2'};
//window.webkit.messageHandlers.playSound.postMessage(messageToPost);
4.2.3、在代理中实现
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
NSLog(@"%@", message.body);
if ([message.name isEqualToString:NSStringFromSelector(@selector(playSound))]) {
[self playSound];
}
}
4.2.4、注意addScriptMessageHandler会引起循环引用;
4.3、JSExport
定义一个继承JSExport协议的子协议JSubPrototocol:
@protocol JSubPrototocol <JSExport>
//注意多个参数的使用JSExportAs
JSExportAs(fullName,- (void)fullName:(NSString*)name address:(NSString*)address);
- (void)jsexportPrint;
@end
定义一个类concrete实现JSubPrototocol
实例化JSContext* jsContext = [[JSContexnt alloc]init];
jsContext[@"person"] = [[concrete alloc] init];
确保调用js的地方处于同一jsContext中:
person.fullName("aimsgmiss","四川省")
person.jsexportPrint();