如何在Swift 2.0中实现copyWithZone?

时间:2015-11-13 06:46:33

标签: ios arrays swift swift2 nscopying

以下代码是用Swift 2.0编写的,用于创建dispatch_block_t

数组
let a: dispatch_block_t = {
    self.pickImages()
}
let b: dispatch_block_t = {
    self.takePicture()
}
let c: dispatch_block_t = {
    self.pickVideos()
}
let d: dispatch_block_t = {
    self.shootVideo()
}
let e: dispatch_block_t = {
    self.recordAudio()
}
let f: dispatch_block_t = {
    self.closeView()
}

let block1 = Block(block: a)
let block2 = Block(block: b)
let block3 = Block(block: c)
let block4 = Block(block: d)
let block5 = Block(block: e)
let block6 = Block(block: f)

let actionsArray: NSArray = [block1, block2, block3, block4, block5, block6]

Block类定义如下,

class Block: NSObject, NSCopying {
    var block: dispatch_block_t

    init(block: dispatch_block_t){
        self.block = block
    }

    func copyWithZone(zone: NSZone) -> AnyObject {
        return self.block as! AnyObject
    }
}

我可以使用上面的代码创建一个dispatch_block_t数组。但是,我需要将此数组作为参数传递给另一个函数,并且我在传递此数组时面临一个问题。

我在按钮点击事件

上调用此函数
menuView = btSimplePopUP(itemImage: imgs as [AnyObject],
    andTitles: titles as [AnyObject],
    andActionArray:  actionsArray as [AnyObject],
    addToViewController: self) 

执行以下代码时出现错误,

- (instancetype)initWithImage:(UIImage *)image title:(NSString *)title action:(dispatch_block_t)action {
if ((self = [super init])) {
    _title = [title copy];
    _imageView = [[UIImageView alloc]initWithImage:image];
    _action = [action copy];
}

return self;
}

错误是,

  

无法转换类型'() - >的值()' (0x15164018)到' Swift.AnyObject' (0x101e500c)。

我在copyWithZone类的Block函数中收到此错误。

可以在这里查看btSimplePopUp的完整源代码, https://github.com/balram3429/btSimplePopUp/blob/master/btSimplePopUp/btSimplePopUP.m

2 个答案:

答案 0 :(得分:1)

dispatch_block_t是一个结构,而不是一个对象。实际上它是一个C结构。我不明白为什么你需要使用dispatch_block_t,为什么不只是通过闭包。如果必须将它传递给dispatch_函数,请将其包装在调用站点的dispatch_block_t中。

为了解决这个问题:

在Swift中,dispatch_block_t只是() -> ()的别名,即返回Void的void函数/闭包。所以你可以简单地说

let a = { self.pickImages() }
// etc

let actionArray = [ a, b, c, ...]

但是,pickImages是一个具有相同类型的函数(从技术角度讲它是self,但不要担心这意味着什么)所以你可以忘记a,b ,c位,只是这样做

let actionArray = [ self.pickImages, self.takePhoto, ... ]

在Swift中,您可以使用其中一个"对象"只要你有一个dispatch_block_t的参数,就在那个数组中。

dispatch_after(someTime, dispatch_get_main_queue(), actionArray[0])

答案 1 :(得分:0)

你需要修改你的Objc框架。你的btSimplePopUP应该像这个样本中的ActionContainer一样工作。 ActionObject是Swift dispatch_block_t的盒装版本。如何在代码中将其拆箱?请参阅ActionContainer作业函数。

//
//  Actions.h
//  test
//


#ifndef Actions_h
#define Actions_h
#import <Foundation/Foundation.h>

@interface ActionObject : NSObject
@property (nonatomic, copy) dispatch_block_t action;
@end


@interface ActionContainer : NSObject
@property  NSArray * actions;
-(void)job;
@end

#endif /* Actions_h */

...

//
//  Actions.m
//  test
//


#import <Foundation/Foundation.h>
#import "Actions.h"


@implementation ActionObject

-(instancetype)initWithAction: (dispatch_block_t)someaction {
    if ((self = [super init])) {
        _action = [someaction copy];
    }
    return self;
}

@end

@implementation ActionContainer
-(void)job {
    if (_actions != nil) {
        NSUInteger count = _actions.count;
        NSUInteger i;
        for (i = 0; i < count; i++) {
            ActionObject *action = _actions[i];
            action.action();
        }

    }
}

@end

...

//
//  Use this file to import your target's public headers that you would like to expose to Swift.
//

#import "Actions.h"

...

//
//  main.swift
//  test
//


import Foundation

let a = ActionObject()
a.action = {
    print("swift a action")
}
let b = ActionObject()
b.action = {
    print("swift b action")
}
let arr: NSArray = [a,b]

let actions = ActionContainer()
actions.actions = arr as [AnyObject]
actions.job()

产生

swift a action
swift b action
Program ended with exit code: 0

...

@implementation ActionContainer
-(void)job {
    if (_actions != nil) {
        NSUInteger count = _actions.count;
        NSUInteger i;
        for (i = 0; i < count; i++) {
            ActionObject *action = _actions[i];
            // myAction is 'unboxed' swift block
            // you can save it, run it
            // somwhere in you ObjectiveC code
            dispatch_block_t myAction = action.action;
            // run it
            myAction();
        }

    }
}