I'm using Swift to make a game in SpriteKit.
In Objective-C I could use the following method:
(void)enumerateChildNodesWithName:(NSString *)name usingBlock:(void (^)(SKNode *node, BOOL *stop))block
to perform actions on that *node, but I can't get this function working in Swift. Basically, I don't know how to reference that node in Swift.
This is the code I'm using, but I'm having trouble with the "usingBlock:" part. I've tried many things for many hours, but have not succeeded. Help please!
func spawnEnemy() -> () {
let enemy = SKSpriteNode(imageNamed: "enemy")
enemy.name = "enemy"
enemy.position = CGPointMake(100, 100)
self.addChild(enemy)
}
func checkCollisions() -> () {
self.enumerateChildNodesWithName("enemy", usingBlock: ((SKNode!, CMutablePointer<ObjCBool>) -> Void)?)
}
For now, don't trust autocomplete to insert the code you need — it drops in signatures from the "header", but a block signature is not the same as the declaration you need when inserting your own closure for a block parameter.
The formal way to write a closure would be to replicate the signature inside braces, adding local parameter names and using the in keyword to mark the start of the closure body:
self.enumerateChildNodesWithName("enemy", usingBlock: {
(node: SKNode!, stop: UnsafeMutablePointer <ObjCBool>) -> Void in
// do something with node or stop
})
But Swift's type inference means you don't have to write that much. Instead, you can just name the parameters, because their type (as well as the closure's return type) is known:
self.enumerateChildNodesWithName("enemy", usingBlock: {
node, stop in
// do something with node or stop
})
You can also use trailing closure syntax:
self.enumerateChildNodesWithName("enemy") {
node, stop in
// do something with node or stop
}
(You can even drop the local parameter names and refer to parameters by position — e.g. $0 for node — but here isn't a great place to do that because it makes your code far less readable. It's best to reserve $0 and friends for closures where it's blindingly obvious what the parameters are, like the closures you use with map and sort.)
See Closures in The Swift Programming Language for further explanation.
Also, because stop is an UnsafeMutablePointer, the syntax for using it is a bit different than in ObjC: set stop.memory = true to break out of enumeration.
Related
I'm developing an iOS app in Swift4 with an Object-C framework called 'YapDatabase'. There is an Object-C function with a block like this in class 'YapDatabaseConnection':
- (void)readWithBlock:(void (^)(YapDatabaseReadTransaction *transaction))block;
I use the function in this way:
static func readNovelIds() -> [String]? {
let account = XFAccountManager.share().account
var events: [XFNovelClickEvent]?
OTRDatabaseManager.shared.readOnlyDatabaseConnection?.read({ (transaction) in
events = XFNovelClickEvent.allNovelClickEvents(accountId: account.uniqueId, transaction: transaction)
})
guard let clickEvents = events else {
return nil
}
let readNovelsIds = clickEvents.map {
$0.bookId ?? ""
}
return readNovelsIds
}
I thought the closure will be executed immediately after the 'events' parameter declared. In fact, the closure doesn't be executed before result returns. To search the reason, I open the file named 'YapDatabaseConnection.h(Interface)' generated by Xcode (with cmd+shift+o), found the function has been translate to Swift in this way:
open func read(_ block: #escaping (YapDatabaseReadTransaction) -> Void)
So, how do I use this function in a #noescap way?
As the caller, you can't change when the closure is executed. That's up to the read() function. If you control that function, you'll need to modify it to call the closure immediately. If you don't control it, then you can't modify how it behaves.
You can convert an asynchronous call into a synchronous call using a DispatchGroup as described in Waiting until the task finishes. However, you can't make a database call on the main queue; you risk crashing the app. As a general rule, you should just use async calls in this case (i.e. make readNovelIds also be asynchronous and take a completion handler).
The reason why Xcode bridged the objective-c block as #escaping is because the block may be executed after the function return.
Since you don’t own YapDatabase, you couldn’t modify the source code to make it non-escaped, so you may wanna make your readNovelIds function takes a closure as parameter and pass the return value through closure.
static func readNovelIds(resultHandler: #escaping ([String]?) -> ()) {
let account = XFAccountManager.share().account
var events: [XFNovelClickEvent]?
OTRDatabaseManager.shared.readOnlyDatabaseConnection?.read({ (transaction) in
events = XFNovelClickEvent.allNovelClickEvents(accountId: account.uniqueId, transaction: transaction)
if let clickEvents = events {
let readNovelsIds = clickEvents.map {
$0.bookId ?? ""
}
resultHandler(readNovelsIds)
}
resultHandler(nil)
})
}
If the method is in fact synchronous (i.e. it will not allow the block to escape its context), the Objective C header method should be decorated with NS_NOESCAPE. Looking at the documentation (which does say it is synchronous), and the implementation, it should be annotated that way.
- (void)readWithBlock:(void (NS_NOESCAPE ^)(YapDatabaseReadTransaction *transaction))block;
That, I believe, should allow the Swift interface importer to add the #noescaping declaration. You should probably file a bug request on the YapDatabase project; they can change it there.
Consider the pattern where there are several states registered with a dispatcher and each state knows what state to transition to when it receives an appropriate event. This is a simple state transition pattern.
struct Dispatcher {
states: HashMap<Uid, Rc<RefCell<State>>>,
}
impl Dispatcher {
pub fn insert_state(&mut self, state_id: Uid, state: Rc<RefCell<State>>) -> Option<Rc<RefCell<State>>> {
self.states.insert(state_id, state)
}
fn dispatch(&mut self, state_id: Uid, event: Event) {
if let Some(mut state) = states.get_mut(&state_id).cloned() {
state.handle_event(self, event);
}
}
}
trait State {
fn handle_event(&mut self, &mut Dispatcher, Event);
}
struct S0 {
state_id: Uid,
move_only_field: Option<MOF>,
// This is pattern that concerns me.
}
impl State for S0 {
fn handle_event(&mut self, dispatcher: &mut Dispatcher, event: Event) {
if event == Event::SomeEvent {
// Do some work
if let Some(mof) = self.mof.take() {
let next_state = Rc::new(RefCell::new(S0 {
state_id: self.state_id,
move_only_field: mof,
}));
let _ = dispatcher.insert(self.state_id, next_state);
} else {
// log an error: BUGGY Logic somewhere
let _ = dispatcher.remove_state(&self.state_id);
}
} else {
// Do some other work, maybe transition to State S2 etc.
}
}
}
struct S1 {
state_id: Uid,
move_only_field: MOF,
}
impl State for S1 {
fn handle_event(&mut self, dispatcher: &mut Dispatcher, event: Event) {
// Do some work, maybe transition to State S2/S3/S4 etc.
}
}
With reference to the inline comment above saying:
// This is pattern that concerns me.
S0::move_only_field needs to be an Option in this pattern because self is borrowed in handle_event, but I am not sure that this is best way to approach it.
Here are the ways I can think of with demerits of each one:
Put it into an Option as I have done: this feels hacky and every time I need
to check the invariant that the Option is always Some otherwise
panic! or make it a NOP with if let Some() = and ignore
the else clause, but this causes code-bloat. Doing an unwrap
or bloating the code with if let Some() feels a bit off.
Get it into a shared ownership Rc<RefCell<>>: Need to heap allocate
all such variables or construct another struct called Inner or
something that has all these non-clonable types and put that into an
Rc<RefCell<>>.
Pass stuff back to Dispatcher indicating it to basically remove us
from the map and then move things out of us to the next State which
will also be indicated via our return value: Too much coupling,
breaks OOP, does not scale as Dispatcher needs to know about all the
States and needs frequent updating. I don't think this is a good
paradigm, but could be wrong.
Implement Default for MOF above: Now we can mem::replace it with
the default while moving out the old value. The burden of panicking OR
returning an error OR doing a NOP is now hidden in implementation of
MOF. The problem here is we don't always have the access to MOF
type and for those that we do, it again takes the point of bloat
from user code to the code of MOF.
Let the function handle_event take self by move as fn handle_event(mut self, ...) -> Option<Self>: Now instead of Rc<RefCell<>> you will need to have Box<State> and move it out each time in the dispatcher and if the return is Some you put it back. This almost feels like a sledgehammer and makes many other idioms impossible, for instance if I wanted to share self further in some registered closure/callback I would normally put a Weak<RefCell<>> previously but now sharing self in callbacks etc is impossible.
Are there any other options? Is there any that is considered the "most idiomatic" way of doing this in Rust?
Let the function handle_event take self by move as fn handle_event(mut self, ...) -> Option<Self>: Now instead of Rc<RefCell<>> you will need to have Box<State> and move it out each time in the dispatcher and if the return is Some you put it back.
This is what I would do. However, you don't need to switch from Rc to Box if there is only one strong reference: Rc::try_unwrap can move out of an Rc.
Here's part of how you might rewrite Dispatcher:
struct Dispatcher {
states: HashMap<Uid, Rc<State>>,
}
impl Dispatcher {
fn dispatch(&mut self, state_id: Uid, event: Event) {
if let Some(state_ref) = self.states.remove(&state_id) {
let state = state_ref.try_unwrap()
.expect("Unique strong reference required");
if let Some(next_state) = state.handle_event(event) {
self.states.insert(state_id, next_state);
}
} else {
// handle state_id not found
}
}
}
(Note: dispatch takes state_id by value. In the original version, this wasn't necessary -- it could have been changed to pass by reference. In this version, it is necessary, since state_id gets passed to HashMap::insert. It looks like Uid is Copy though, so it makes little difference.)
It's not clear whether state_id actually needs to be a member of the struct that implements State anymore, since you don't need it inside handle_event -- all the insertion and removal happens inside impl Dispatcher, which makes sense and reduces coupling between State and Dispatcher.
impl State for S0 {
fn handle_event(self, event: Event) -> Option<Rc<State>> {
if event == Event::SomeEvent {
// Do some work
let next_state = Rc::new(S0 {
state_id: self.state_id,
move_only_field: self.mof,
});
Some(next_state)
} else {
// Do some other work
}
}
}
Now you don't have to handle a weird, should-be-impossible corner case where the Option is None.
This almost feels like a sledgehammer and makes many other idioms impossible, for instance if I wanted to share self further in some registered closure/callback I would normally put a Weak<RefCell<>> previously but now sharing self in callbacks etc is impossible.
Because you can move out of an Rc if you have the only strong reference, you don't have to sacrifice this technique.
"Feels like a sledgehammer" might be subjective, but to me, what a signature like fn handle_event(mut self, ...) -> Option<Self> does is encode an invariant. With the original version, each impl State for ... had to know when to insert and remove itself from the dispatcher, and whether it did or not was uncheckable. For example, if somewhere deep in the logic you forgot to call dispatcher.insert(state_id, next_state), the state machine wouldn't transition, and might get stuck or worse. When handle_event takes self by-value, that's not possible anymore -- you have to return the next state, or the code simply won't compile.
(Aside: both the original version and mine do at least two hashtable lookups each time dispatch is called: once to get the current state, and again to insert the new state. If you wanted to get rid of the second lookup, you could combine approaches: store Option<Rc<State>> in the HashMap, and take from the Option instead of removing it from the map entirely.)
libc's error handling is usually to return something < 0 in case of an error. I find myself doing this over and over:
let pid = fork()
if pid < 0 {
// Please disregard the fact that `Err(pid)`
// should be a `&str` or an enum
return Err(pid);
}
I find it ugly that this needs 3 lines of error handling, especially considering that these tests are quite frequent in this kind of code.
Is there a way to return an Err in case fork() returns < 0?
I found two things which are close:
assert_eq!. This needs another line and it panics so the caller cannot handle the error.
Using traits like these:
pub trait LibcResult<T> {
fn to_option(&self) -> Option<T>;
}
impl LibcResult<i64> for i32 {
fn to_option(&self) -> Option<i64> {
if *self < 0 { None } else { Some(*self) }
}
}
I could write fork().to_option().expect("could not fork"). This is now only one line, but it panics instead of returning an Err. I guess this could be solved using ok_or.
Some functions of libc have < 0 as sentinel (e.g. fork), while others use > 0 (e.g. pthread_attr_init), so this would need another argument.
Is there something out there which solves this?
As indicated in the other answer, use pre-made wrappers whenever possible. Where such wrappers do not exist, the following guidelines might help.
Return Result to indicate errors
The idiomatic Rust return type that includes error information is Result (std::result::Result). For most functions from POSIX libc, the specialized type std::io::Result is a perfect fit because it uses std::io::Error to encode errors, and it includes all standard system errors represented by errno values. A good way to avoid repetition is using a utility function such as:
use std::io::{Result, Error};
fn check_err<T: Ord + Default>(num: T) -> Result<T> {
if num < T::default() {
return Err(Error::last_os_error());
}
Ok(num)
}
Wrapping fork() would look like this:
pub fn fork() -> Result<u32> {
check_err(unsafe { libc::fork() }).map(|pid| pid as u32)
}
The use of Result allows idiomatic usage such as:
let pid = fork()?; // ? means return if Err, unwrap if Ok
if pid == 0 {
// child
...
}
Restrict the return type
The function will be easier to use if the return type is modified so that only "possible" values are included. For example, if a function logically has no return value, but returns an int only to communicate the presence of error, the Rust wrapper should return nothing:
pub fn dup2(oldfd: i32, newfd: i32) -> Result<()> {
check_err(unsafe { libc::dup2(oldfd, newfd) })?;
Ok(())
}
Another example are functions that logically return an unsigned integer, such as a PID or a file descriptor, but still declare their result as signed to include the -1 error return value. In that case, consider returning an unsigned value in Rust, as in the fork() example above. nix takes this one step further by having fork() return Result<ForkResult>, where ForkResult is a real enum with methods such as is_child(), and from which the PID is extracted using pattern matching.
Use options and other enums
Rust has a rich type system that allows expressing things that have to be encoded as magic values in C. To return to the fork() example, that function returns 0 to indicate the child return. This would be naturally expressed with an Option and can be combined with the Result shown above:
pub fn fork() -> Result<Option<u32>> {
let pid = check_err(unsafe { libc::fork() })? as u32;
if pid != 0 {
Some(pid)
} else {
None
}
}
The user of this API would no longer need to compare with the magic value, but would use pattern matching, for example:
if let Some(child_pid) = fork()? {
// execute parent code
} else {
// execute child code
}
Return values instead of using output parameters
C often returns values using output parameters, pointer parameters into which the results are stored. This is either because the actual return value is reserved for the error indicator, or because more than one value needs to be returned, and returning structs was badly supported by historical C compilers.
In contrast, Rust's Result supports return value independent of error information, and has no problem whatsoever with returning multiple values. Multiple values returned as a tuple are much more ergonomic than output parameters because they can be used in expressions or captured using pattern matching.
Wrap system resources in owned objects
When returning handles to system resources, such as file descriptors or Windows handles, it good practice to return them wrapped in an object that implements Drop to release them. This will make it less likely that a user of the wrapper will make a mistake, and it makes the use of return values more idiomatic, removing the need for awkward invocations of close() and resource leaks coming from failing to do so.
Taking pipe() as an example:
use std::fs::File;
use std::os::unix::io::FromRawFd;
pub fn pipe() -> Result<(File, File)> {
let mut fds = [0 as libc::c_int; 2];
check_err(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
Ok(unsafe { (File::from_raw_fd(fds[0]), File::from_raw_fd(fds[1])) })
}
// Usage:
// let (r, w) = pipe()?;
// ... use R and W as normal File object
This pipe() wrapper returns multiple values and uses a wrapper object to refer to a system resource. Also, it returns the File objects defined in the Rust standard library and accepted by Rust's IO layer.
The best option is to not reimplement the universe. Instead, use nix, which wraps everything for you and has done the hard work of converting all the error types and handling the sentinel values:
pub fn fork() -> Result<ForkResult>
Then just use normal error handling like try! or ?.
Of course, you could rewrite all of nix by converting your trait to returning Results and including the specific error codes and then use try! or ?, but why would you?
There's nothing magical in Rust that converts negative or positive numbers into a domain specific error type for you. The code you already have is the correct approach, once you've enhanced it to use a Result either by creating it directly or via something like ok_or.
An intermediate solution would be to reuse nix's Errno struct, perhaps with your own trait sugar on top.
so this would need another argument
I'd say it would be better to have different methods: one for negative sentinel values and one for positive sentinel values.
I am porting some AppDelegate code for a plugin Objective-C to Swift.
My Objective-C is pretty good but I am stumped at understanding whats going on here. This is the code I am stuck on porting:
void (^safeHandler)(UIBackgroundFetchResult) = ^(UIBackgroundFetchResult result){
dispatch_async(dispatch_get_main_queue(), ^{
completionHandler(result);
});
};
I understand that the the ^ is for code blocks, but looking at this as a whole I am lost as to what is going on and how to port this to Swift.
I don't understand how there are two bracketed portions here:
void (^safeHandler)(UIBackgroundFetchResult)
If you can advise what that syntax is and how to port to Swift I would greatly appreciate it!
It's a block, which is a closure in Swift. This block is named safeHandler and takes a UIBackgroundFetchResult parameter and returns void.
This is the equivalent type:
let safeHandler: (UIBackgroundFetchResult) -> ()
And the whole thing would be
let safeHandler: (UIBackgroundFetchResult) -> () = { result in
dispatch_async(dispatch_get_main_queue()) {
completionHandler(result)
}
}
Note: block syntax is notoriously wonky. You can use this site to see the various block syntax forms: http://goshdarnblocksyntax.com/
I've run into a situation while using a library called TransitionKit (helps you write state machines) where I am want to supply entry and exit actions in the form of a callback.
Sadly, the callbacks include two completely useless parameters. A typical block has to look like this:
^void (TKState *state, TKStateMachine *stateMachine) {
// I TOTALLY don't want parameters `state` or `stateMachine` used here
};
(this is an anonymous code block. Read up on blocks here if you're unclear)
As I've noted in the comment, I really don't want those parameters even mentioned in the body there. I've tried simply removing the parameter names like suggested in this question like so:
^void (TKState *, TKStateMachine *) {
// I foobar all I like here
};
but sadly the code won't compile then :(.
How can I enforce this non-usage of parameters in code?
This is what I could come up with. Quite a hack and relies on the GCC poison pragma, which is not standard but a GNU extension - although, given that you are probably compiling this with clang anyway, it should not be a problem.
#define _state state
#define _stateMachine stateMachine
#pragma GCC poison state stateMachine
Then this compiles:
^(TKState *_state, TKStateMachine *_stateMachine) {
do_something();
}
But this doesn't:
^(TKState *_state, TKStateMachine *_stateMachine) {
do_something(state, stateMachine);
}
You could just have a function that took one kind of block, and returned another, like this:
#class TKState, TKStateMachine; // here so this will compile
typedef void (^LongStateBlock)(TKState *state, TKStateMachine *stateMachine);
static inline LongStateBlock Adapter(void(^block)()) {
void(^heapBlock)() = [block copy]; // forces block to be on heap rather than stack, a one-time expense
LongStateBlock longBlock = ^(TKState *s __unused, TKStateMachine *sm __unused) {
heapBlock();
};
// this is the non-ARC, MRR version; I'll leave ARC for the interested observer
[heapBlock release];
return [[longBlock copy] autorelease];
}
And in practice:
// this represents a library method
- (void)takesLongStateBlock:(LongStateBlock)longBlock
{
// which hopefully wouldn't look exactly like this
if (longBlock) longBlock(nil, nil);
}
- (void)yourRandomMethod
{
[self takesLongStateBlock:^(TKState *state, TKStateMachine *stateMachine) {
NSLog(#"Gratuitous parameters, AAAAHHHH!");
}];
[self takesLongStateBlock:Adapter(^{
NSLog(#"So, so clean.");
})];
}
The whole thing is gisted, and should compile inside any class. It does what you expect when you call -yourRandomMethod.
AFAIK there is no way to do what you want when you are creating a block, you can only miss the parameter names when you are declaring a block variable(a reference to a block, to avoid misunderstandings)
So here you can miss the param names:
void (^myBlock)(SomeClass *);
But not when you create a block:
myBlock = ^(SomeClass *o)
{
};
I'd write
^void (TKState *unused_state, TKStateMachine *unused_stateMachine) {
// Anyone using unused_state or unused_stateMachine gets what they deserve.
};
Of course someone can use the parameters. But then whatever you do, they can change the code. If someone is intent on shooting themselves in the foot, there is no stopping them.