NSInvocation和NSUndoManager的使用和详解

知识点

NS_SWIFT_UNAVAILABLE("NSInvocation and related APIs not available")在swift中不能使用
NSInvocation可以直接调用某个对象的方法.
NSInvocation和NSMethodSignature搭配使用,可以访问某个类内部定义所有方法私有的公开的都可以.
NSMethodSignature是方法的签名,可以用来获取参数数量,返回值类型,返回值长度,指定参数的类型等,具体见API

NSInvocation的使用

#import "InvocationViewController.h"
#import "UndoManager.h"
@interface InvocationViewController ()

@end

@implementation InvocationViewController
{
    UndoManager * undoManage;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    undoManage = [[UndoManager alloc]init];
    //获取方法的对象
    //publicInvocation是有返回值的
    NSInvocation * publicInvocation = [self buildPublicInvocation];
    //privateInvocation无参无返回值
    NSInvocation * privateInvocation = [self buildPrivateInvocation];
    
    //有参数的话需要设置参数
    //atIndex是在方法中参数的位置,从左往右数,不能是0和1,要记得0和1已经被占用了即可.
    NSString * object = @"object";
    NSString * object1 = @"object1";
    NSString * object2 = @"object2";

    [publicInvocation setArgument:&object atIndex:2];
    [publicInvocation setArgument:&object1 atIndex:3];
    [publicInvocation setArgument:&object2 atIndex:4];
    //设置接收返回值的对象
    NSString * returnValue;
    [publicInvocation setReturnValue:&returnValue];
    //调用方法
    [publicInvocation invoke];
    //接收返回值
    NSLog(@"%@",returnValue);
    //打印返回值
    [publicInvocation getReturnValue:&returnValue];
    NSLog(@"publicInvocation:%@",returnValue);
    
    //调用私有方法
    [privateInvocation invoke];
    
    
    // Do any additional setup after loading the view.
}
- (NSInvocation *)buildPublicInvocation{

    //初始化方法的签名,需要调用谁的方法就用谁去创建签名,这里是UndoManager这个类的方法.
    //初始化方法的签名有两种这里是使用的类方法还有一种是对象方法
    NSMethodSignature * signature = [UndoManager instanceMethodSignatureForSelector:@selector(invocationTestObject:withObject1:withObject2:)];
    //返回invocation对象
    NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:signature];
    //设置invocation的目标对象
    [invocation setTarget:undoManage];
    //设置需要调用的方法,切记需要和signature中的方法一致
    [invocation setSelector:@selector(invocationTestObject:withObject1:withObject2:)];
    return invocation;
}

- (NSInvocation *)buildPrivateInvocation{
    //初始化方法的签名,需要调用谁的方法就用谁去创建签名,这里是UndoManager这个类的方法.
    //初始化方法的签名有两种这里是使用的对象方法
    NSMethodSignature * signature = [undoManage methodSignatureForSelector:@selector(testMethodSignature)];
    NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:signature];
    [invocation setTarget:undoManage];
    [invocation setSelector:@selector(testMethodSignature)];
    return invocation;
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end

//
//  UndoManager.h
//  ObjectMode
//
//  Created by 董德帅 on 2020/6/25.
//  Copyright © 2020 九天. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface UndoManager : NSObject
- (NSString *)invocationTestObject:(NSString *)object withObject1:(NSString *)object1 withObject2:(NSString *)object2;
@end

NS_ASSUME_NONNULL_END
//
//  UndoManager.m
//  ObjectMode
//
//  Created by 董德帅 on 2020/6/25.
//  Copyright © 2020 九天. All rights reserved.
//

#import "UndoManager.h"

@implementation UndoManager
{

}
- (instancetype)init
{
    self = [super init];
    if (self) {

    }
    return self;
}

- (void)testMethodSignature{
    NSLog(@"私有方法也可以被外界访问");
}

- (NSString *)invocationTestObject:(NSString *)object withObject1:(NSString *)object1 withObject2:(NSString *)object2{
    NSLog(@"%@,%@,%@",object,object1,object2);
    return @"return";
}


@end

最终的打印结果,可以发现私有的和公开的都能成功的被调用,对于有返回值的必须调用getReturnValue这个方法后设置的接收返回值的对象才会有参数.


截屏2020-06-26下午6.54.25.png

NSUndoManager和NSInvocation结合使用

NSUndoManager详解

//
//  InvocationViewController.m
//  ObjectMode
//
//  Created by 董德帅 on 2020/6/25.
//  Copyright © 2020 九天. All rights reserved.
//

#import "InvocationViewController.h"
#import "UndoAndInvocation.h"
@interface InvocationViewController ()

@end

@implementation InvocationViewController
{
    UndoAndInvocation * undoInvocation;
    NSUndoManager * myUndoManager;
}
- (void)viewDidLoad {
    [super viewDidLoad];

    
    //NSUndoManager和NSInvocation的结合
    [self undoAndInvocation];
    // Do any additional setup after loading the view.
}

- (void)undoAndInvocation{
    undoInvocation = [UndoAndInvocation new];
    myUndoManager = [[NSUndoManager alloc]init];
    
    NSString * object = @"测试专用字符串";
    
    [self addObject:object];
    //打印数据
    [undoInvocation printData];

    //执行撤销操作
    [myUndoManager undo];
    //打印数据
    [undoInvocation printData];

    //执行恢复操作
    [myUndoManager redo];
    //打印数据
    [undoInvocation printData];
}

- (void)addObject:(NSString *)object{
    NSInvocation * invocation = [self buildAddInvocation];
    [invocation setArgument:&object atIndex:2];
    [invocation invoke];
    [[myUndoManager prepareWithInvocationTarget:self] removeObject:object];;
    
}

- (void)removeObject:(NSString *)object{
    
    NSInvocation * invocation = [self buildRemovaInvocation];
    [invocation setArgument:&object atIndex:2];
    [invocation invoke];
    [[myUndoManager prepareWithInvocationTarget:self] addObject:object];
}

- (NSInvocation *)buildAddInvocation{
    
    NSMethodSignature * signature = [UndoAndInvocation instanceMethodSignatureForSelector:@selector(addObject:)];
    NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:signature];
    [invocation setSelector:@selector(addObject:)];
    [invocation setTarget:undoInvocation];
    return invocation;
}

- (NSInvocation *)buildRemovaInvocation{
    NSMethodSignature * signature = [UndoAndInvocation instanceMethodSignatureForSelector:@selector(removeObject:)];
    NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:signature];
    [invocation setTarget:undoInvocation];
    [invocation setSelector:@selector(removeObject:)];
    return invocation;
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end
//
//  UndoAndInvocation.h
//  ObjectMode
//
//  Created by 董德帅 on 2020/6/26.
//  Copyright © 2020 九天. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface UndoAndInvocation : NSObject
- (void)addObject:(NSString *)object;
- (void)removeObject:(NSString *)object;

- (void)printData;
@end

NS_ASSUME_NONNULL_END
//
//  UndoAndInvocation.m
//  ObjectMode
//
//  Created by 董德帅 on 2020/6/26.
//  Copyright © 2020 九天. All rights reserved.
//

#import "UndoAndInvocation.h"

@implementation UndoAndInvocation
{
    NSMutableArray * arrData;
}
- (instancetype)init
{
    self = [super init];
    if (self) {
        arrData = [NSMutableArray new];
    }
    return self;
}

- (void)addObject:(NSString *)object{
    [arrData addObject:object];
}

- (void)removeObject:(NSString *)object{
    [arrData removeObject:object];
}

- (void)printData{
    NSLog(@"%@",arrData);
}
@end

代码传送

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。