Reputation: 139
The following code is written in Swift 2.0 to create an array of 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]
And the Block
class is defined as follows,
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
}
}
I could create an array of dispatch_block_t with the above piece of code. But, I need to pass this array as a parameter to another function and I am facing an issue in passing this array.
I am calling this function on a button click event,
menuView = btSimplePopUP(itemImage: imgs as [AnyObject],
andTitles: titles as [AnyObject],
andActionArray: actionsArray as [AnyObject],
addToViewController: self)
And I am getting an error when the following snippet is executed,
- (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;
}
And the error is,
Could not cast value of type '() -> ()' (0x15164018) to 'Swift.AnyObject' (0x101e500c).
I am getting this error in copyWithZone
function of Block
class.
The complete source code for btSimplePopUp can be viewed here, https://github.com/balram3429/btSimplePopUp/blob/master/btSimplePopUp/btSimplePopUP.m
Upvotes: 1
Views: 520
Reputation: 86651
dispatch_block_t
is a struct, not an object. In fact it's a C struct. I don't understand why you need to use a dispatch_block_t, why not just pass the closure around. If you have to pass it to a dispatch_
function wrap it in a dispatch_block_t at the call site.
To Swiftify this:
In Swift, dispatch_block_t
is simply an alias for () -> ()
i.e. a void function/closure returning Void
. So you can simply say
let a = { self.pickImages() }
// etc
let actionArray = [ a, b, c, ...]
However, pickImages
is a function that has the same type (technically it is curried over self
but don't worry about what that means) so you can forget about the a, b, c bit and just do this
let actionArray = [ self.pickImages, self.takePhoto, ... ]
And in Swift, you can use one of the "objects" in that array any time you have a parameter that takes a dispatch_block_t
e.g.
dispatch_after(someTime, dispatch_get_main_queue(), actionArray[0])
Upvotes: 1
Reputation: 17544
You need to modify you Objc framework. your btSimplePopUP should works like ActionContainer from this sample. ActionObject is boxed version of Swift dispatch_block_t. How to unbox it in your code? See ActionContainer job function.
//
// 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()
produce
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();
}
}
}
Upvotes: 0