Swift Block Value Error

Swift Block value error

Don't specify the argument labels when you call blockFinih. You've defined it to have no argument labels. The parameters selectedTags and unSelectedTags can only be used inside the function, not by the caller.

Change:

self.blockFinih(selectedTags: selected, unSelectedTags: unSelected)

to:

self.blockFinih(selected, unSelected)

Use block in Swift giving error Variable used within its own initial value

The Swift compiler is very strict and checks that every variable has
a defined value before it is used. The compiler
does not know that in your case, the closures will be executed only
after the requestReference variable is defined.

In such cases you can use an implicitly unwrapped optional:

var requestReference: String! 
requestReference = self.operation(..., success: {(_ task: URLSessionDataTask, _ responseObject: Any) -> Void in
// ...
delegate.request(with: requestReference, didFinishWithBusinessError: error)
}, failure: {(_ task: URLSessionDataTask, _ error: Error) -> Void in
delegate.request(with: requestReference, didFailWithError: error)
})

An implicitly unwrapped optional is a promise to the compiler:
The variable has no value now, but it will have a value when it is used.

Error handling in block with Swift syntax

In my opinion, you should try very hard to avoid the (Value?, Error?) pattern when you can. It creates bad corner cases since two combinations are illegal. Instead, when possible, I suggest (Value, Error?) any time Value has a sensible "zero". In this case "zero" is "empty array". This matches the ObjC sense very closely, since a nil NSArray is very similar to an empty array.

Doing that, you can substantially simplify this code:

func getDevices(location: NSURL, completion handler:([ChargeDevice], error: NSError?) -> Void) {

// Note that error is marked "var" so we can modify it, and switched from NSError! to NSError?
let task = session.dataTaskWithRequest(request, completionHandler: { (let data, let response, var error: NSError?) -> Void in
var result = [ChargeDevice]()

if error == nil {
// Avoid NSArray and NSDictionary wherever you can in Swift
if let
json = NSJSONSerialization.JSONObjectWithData(data,
options: .AllowFragments,
error: &error
) as? [String:AnyObject],

chargeDevices = json["ChargeDevice"] as? [AnyObject] {
// map is much simpler in this case, but in your full code, for may fine fine
result = chargeDevices.map{ _ in ChargeDevice() }
}
}

dispatch_async(dispatch_get_main_queue(), { () -> Void in
handler(result, error: error)
})
})
}

Note that in your code and my code, incorrect but valid JSON will not generate an error of any kind. It'll just quietly skip through the as? calls. I would probably move all of this JSON work into another function to keep this closure from getting out of hand.

Another approach here is called a Result. My preferred example is Rob Rix's. Even though I've done a lot of work on Result, I've personally find it difficult to bridge to Cocoa cleanly. It's useful if your entire program uses it, and if you encapsulate most Cocoa interaction, but I've found it cumbersome to use as a one-off solution. (Many people would disagree with me here, it's just my experience. Result is definitely worth exploring to form your own opinion.)

Why outside of block swift can't see value assigned to a uninitialized variable in the block?

Well, the message is not very helpful, and that's the problem. This pattern (which I call computed initialization) is perfectly legal and useful and — amazingly — you can even use let instead of var. But you must initialize the uninitialized variable by all possible paths before you use it. So you have:

var v:String
if true {
v = "Hello"
}
print(v) // error

But hold my beer and watch this:

var v:String
if true {
v = "Hello"
} else {
v = "Goodbye"
}
print(v) // fine!

Or even:

let v:String
if true {
v = "Hello"
} else {
v = "Goodbye"
}
print(v) // fine!

Amazing, eh?

Now, you might say: OK, but true will always be true so it's silly to make me fulfill the "all paths" rule. Too bad! The compiler insists anyway, and then lets you off later with a warning that the else won't be executed. But a warning lets you compile; an error doesn't. The truth is that your example is very artificial. But this is a real-life possibility:

let v:String
if self.someBoolProperty {
v = "Hello"
} else {
v = "Goodbye"
}
print(v) // fine!

Not only is this sort of thing legal, it is actually the pattern that Apple recommends under certain slightly tricky circumstances. For instance, it is used in Apple's own example code showing how to use the Swift 5 Result struct:

let result: Result<Int, EntropyError>
if count < AsyncRandomGenerator.entropyLimit {
// Produce numbers until reaching the entropy limit.
result = .success(Int.random(in: 1...100))
} else {
// Supply a failure reason when the caller hits the limit.
result = .failure(.entropyDepleted)
}

How to write a block to return value from one class to another?

Try this may this help you:

    var onLogCompletion:((_ logThing:String) -> ())? = nil

func printerCompletion(currentLog:String) -> Void {
self.onLogCompletion!(currentLog)
}

self.onLogCompletion = { (log) in
print(log)
}

you need to define block before calling of block other wise it will be nil

    objX.onLogCompletionm  = { (log) in
print(log)
}

printerCompletion(currentLog: "New Log")

Sample Image

Completion Block becomes nil in Swift 3

The issue is that you forgot to specify the type of onCompletion. With the declaration of onCompletion you need to also specify its type that it is FetchFilesCompletionBlock.

let onCompletion: FetchFilesCompletionBlock = {(file, error) in
//Your code
}
dataManager.fetchFile(param, onCompletion: onCompletion)

Catching an error from a non-throwing method

You can use the init(exactly:) constructor, it will not throw an error but it will return nil if the value is to large

guard let value = Int(exactly: pow(Double(1000000000), Double(10))) else {
//error handling
}


Related Topics



Leave a reply



Submit