Swift optional inout parameters and nil
It won't compile because the function expecting a reference but you passed nil
. The problem have nothing to do with optional.
By declaring parameter with inout
means that you will assign some value to it inside the function body. How can it assign value to nil
?
You need to call it like
var a : MyClass? = nil
testFunc(&a) // value of a can be changed inside the function
If you know C++, this is C++ version of your code without optional
struct MyClass {};
void testFunc(MyClass &p) {}
int main () { testFunc(nullptr); }
and you have this error message
main.cpp:6:6: note: candidate function not viable: no known conversion from 'nullptr_t' to 'MyClass &' for 1st argument
which is kind of equivalent to the on you got (but easier to understand)
swift How to send &nil to func?
You cannot use a value as an inout
parameter in Swift. You need to create a variable of type CAShapeLayer
, assing it a nil
value and use that as the input parameter to your function.
func setupCircular(circularLayer:inout CAShapeLayer?){
if (circularLayer == nil) {
circularLayer = CAShapeLayer()
}else{
}
}
var circ: CAShapeLayer? = nil
setupCircular(circularLayer: &circ)
How to guarantee that inout argument won't change Type and won't become nil in a function
inout won't accept Generic type , because the reference wants to store value backs to its original value. here is the link for inout https://docs.swift.org/swift-book/LanguageGuide/Functions.html
Need help in using Swift inout with optional
@MartinR makes a good point in the comments: "Why does merge() take inout parameters? The arguments are not modified, so this seems like an unnecessary complication."
The reason for the error is that you have to pass the exact type when using inout
, and DNode
and DNode?
are two different types.newNode
needs to be declared as optional because that is what merge is expecting:
func start(inout newNode: DNode?) {
self.minDNode = merge(&self.minDNode, And: &newNode) // this call now works
}
You probably should rework your code, though, to remove the inout
calls where they aren't needed.
inout param with empty object since nil won't work
There are many things that won’t work here.
You need to give more than []
to declare an array. You need to give some indication of it’s element type. Either in the brackets e.g. [Int]()
or from other context i.e. if test
took an [Int]
arg not an Any
. Otherwise the compiler has no idea what type you mean by []
.
You cannot pass literals (for example, nil
) into an inout
parameter. In fact you can’t pass any kind of immutable value, including temporary objects like [Int]()
, or variables declared with let
. The only things you can pass to an inout
parameter are “lvalues” – that is, things that can be on the left-hand side of an assignment. That means even if you changed this to `test(&Int) it won’t work.
Finally, even if you declare var a = [Int]()
and then try to call test(&a)
you’ll get an error, because the implicit copy of a
from an array to an Any
will result in another immutable temporary, which also can’t be passed as an inout
.
Default optional parameter in Swift function
Optionals and default parameters are two different things.
An Optional is a variable that can be nil
, that's it.
Default parameters use a default value when you omit that parameter, this default value is specified like this: func test(param: Int = 0)
If you specify a parameter that is an optional, you have to provide it, even if the value you want to pass is nil
. If your function looks like this func test(param: Int?)
, you can't call it like this test()
. Even though the parameter is optional, it doesn't have a default value.
You can also combine the two and have a parameter that takes an optional where nil
is the default value, like this: func test(param: Int? = nil)
.
Is there a way to use a Template, and In-Out Parameter and Optional together?
The main problem here is that the generic T
can never itself know if it is of Optional
type or not, which makes successful type conversion to T
tricky for the cases when T
is in fact of type Optional<SomeType>
. We could, ourselves, assert that T
is an optional type (checking Mirror(reflecting: ...).displayStyle == .Optional
etc), however this still doesn't solve conversion to T
right off the bat. Instead, we could use another approach, as follows below.
We can work around the problem by creating two readData(...)
functions, one taking an optional generic inout
parameter, type U?
, and the other one taking an implicitly non-optional generic inout
parameter U
(called only if U?
function cannot be used, hence implicitly only called for non-optionals). These two functions, in turn, are minimal and basically only calls your "core" dataReader(..)
function, where we've made the adjustment that the inout
generic parameter is now explicitly optional, i.e., T?
.
enum ConvertError: ErrorType {
case MissingParameter
case WrongType
}
/* optional inout parameter */
func readData<U>(inout output: U?, _ input: AnyObject?, _ throwError: Bool = true) throws {
try readDataCore(&output, input, throwError)
}
/* non-optional inout parameter */
func readData<U>(inout output: U, _ input: AnyObject?, _ throwError: Bool = true) throws {
var outputOpt : U? = output
try readDataCore(&outputOpt, input, throwError)
output = outputOpt!
/* you could use a guard-throw here for the unwrapping of 'outputOpt', but
note that 'outputOpt' is initialized with a non-nil value, and that it can
never become 'nil' in readDataHelper; so "safe" forced unwrapping here. */
}
/* "core" function */
func readDataCore<T>(inout output: T?, _ input: AnyObject?, _ throwError: Bool = true) throws
{
if (input == nil) {
if (throwError) {
throw ConvertError.MissingParameter
}
}
else {
if let inputObject: T = input as? T {
output = inputObject
}
else if (throwError) {
throw ConvertError.WrongType
}
}
}
As we try this out, we see that we now get the behaviour we're looking for, even if the argument sent as inout
parameter is nil
or Optional
.
Example 1: using optional inout
param with value nil
class Properties
{
var x:Int?
var y:Int?
}
var myJson : [String:Int] = ["data":10]
var originalProperties = Properties()
do {
try readData(&originalProperties.x, myJson["data"], true)
print("originalProperties.x = \(originalProperties.x ?? 0)")
} catch ConvertError.MissingParameter {
print("Missing parameter")
} catch ConvertError.WrongType {
print("Wrong type")
} catch {
print("Unknown error")
}
/* Prints: 'originalProperties.x = 10', ok! */
// try some non-existing key 'foo'
do {
try readData(&originalProperties.x, myJson["foo"], true)
print("originalProperties.x = \(originalProperties.x ?? 0)")
} catch ConvertError.MissingParameter {
print("Missing parameter")
} catch ConvertError.WrongType {
print("Wrong type")
} catch {
print("Unknown error")
}
/* Prints: 'Missing parameter', ok! */
Example 2: using optional inout
param with, however, with a non-optional value
class Properties
{
var x:Int? = 1
var y:Int? = 1
}
var myJson : [String:Int] = ["data":10]
var originalProperties = Properties()
// ...
/* Same results as for Example 1:
'originalProperties.x = 10' and 'Missing parameter' */
Example 3: using non-optional inout
parameter
class Properties
{
var x:Int = 1
var y:Int = 1
}
var myJson : [String:Int] = ["data":10]
var originalProperties = Properties()
// ...
/* Same results as for Example 1:
'originalProperties.x = 10' and 'Missing parameter' */
NULL parameter in Swift
Your Objective-C method has nullable pointers as parameters,
in Swift 3 that would be an optional UnsafeMutablePointer
:
func getRect(aRectRef: UnsafeMutablePointer<CGRect>?, bRectRef: UnsafeMutablePointer<CGRect>?) {
if let aRectPtr = aRectRef {
aRectPtr.pointee = CGRect(x: 1, y: 2, width: 3, height: 4)
}
if let bRectPtr = bRectRef {
bRectPtr.pointee = CGRect(x: 5, y: 6, width: 7, height: 8)
}
}
var rect = CGRect.zero
getRect(aRectRef: &rect, bRectRef: nil)
print(rect) // (1.0, 2.0, 3.0, 4.0)
So you can pass nil
as an argument. What you can not do
(in contrast to Objective-C) is to pass the address of an uninitialized variable, rect
must be initialized here.
The same can be written more compactly as
func getRect(aRectRef: UnsafeMutablePointer<CGRect>?, bRectRef: UnsafeMutablePointer<CGRect>?) {
aRectRef.map { $0.pointee = CGRect(x: 1, y: 2, width: 3, height: 4) }
bRectRef.map { $0.pointee = CGRect(x: 5, y: 6, width: 7, height: 8) }
}
Swift 4: Escaping closures can only capture inout parameters explicitly by value
The error is described in detail in this answer.
The problem with your code is that the first closure
fileprivate func fetchUserAvatar(_ internalUrl : URL, externalUrl : URL,_ task : inout URLSessionTask?, completion : @escaping (_ image : UIImage?) -> ()) {
fetchImage(externalUrl, task: &task, completion: { image in // <-- HERE --
if image == nil {
is an escaping closure. So when the code
if image == nil {
self.fetchImage(internalUrl, task: &task, completion: completion) // <-- HERE --
} else {
tries to write to the task
variable, the original fetchUserAvatar
call has already completed.
Note: I have written comments like this <-- HERE --
into the snippets, to clarify which line I am talking about. Also, please make sure to check out the answer that I linked above, because it will clarify everything..
The bad news is that you will have to refactor the code a bit to fix the error. You'll need to change the signatures of both fetchUserThumbnailAvatar
, as well as fetchUserAvatar
for that, and that will break callers; so the callers have to be changed as well. Therefore I cannot fix it for you, because the fix depends on code that I don't have.
Related Topics
In Swift 3, How to Calculate the Factorial When the Result Becomes Too High
Reasons to Include Function in Protocol Definition VS. Only Defining It in the Extension
Dismiss Keyboard with a Uitextview
Lazy Initialisation and Retain Cycle
Concatenate Two Audio Files in Swift and Play Them
Swiftui: Can't Get the Transition of a Detailview to a Zstack in the Mainview to Work
How to Get the Index of the Element in the List in Swiftui When the List Is Populated with the Array
How to Satisfy Swift Protocol and Add Defaulted Arguments
What Are "Intervals" in Swift Ranges
Multiple Workers in Swift Command Line Tool
How to Use an Nsattributedstring with a Scrollview in Swiftui
Find Difference in Seconds Between Nsdates as Integer Using Swift
A Swift Protocol Requirement That Can Only Be Satisfied by Using a Final Class
Why Is Manually Setup Root View Controller Showing Black Screen