How to use UnsafeMutablePointer in Swift 3? - ios

I have the following code written in Swift 2.2:
let keyData = NSMutableData(length: 64)!
SecRandomCopyBytes(kSecRandomDefault, 64, UnsafeMutablePointer<UInt8>(keyData.mutableBytes))
XCode 8 highlights that second line and claims that
Cannot invoke initializer for type 'UnsafeMutablePointer<_>' with an
argument list of type '(UnsafeMutableRawPointer)'
While I appreciate XCode telling me this, I don't quite understand how to change the UnsafeMutableRawPointer to be acceptable.
Does anyone know how to convert this code into Swift 3?

I recommend you to work with Data rather than NSData in Swift 3.
var keyData = Data(count: 64)
let result = keyData.withUnsafeMutableBytes {mutableBytes in
SecRandomCopyBytes(kSecRandomDefault, keyData.count, mutableBytes)
}
withUnsafeMutableBytes(_:) is declared as a generic method, so, in simple cases such as this, you can use it without specifying element type.

Related

Don't understand "Extra argument 'repeatedValue' in call"

What could be wrong with:
let myArray = [UInt](count: 256, repeatedValue: 0)
that leads to the error Extra argument 'repeatedValue' in call?
I found this in existing code I'm adding to my Swift 5 app.
This is not Swift 5. The initializer name is init(repeating:count:) since Swift 3.

Could not cast value of type 'Swift.UInt64' (0x10dddde88) to 'Swift.AnyObject' (0x12129d018)

In Swift 2.3, I must cast UInt64 to AnyObject with as!. But It's as in Swift 3. Once I cast this in Swift 2.3, it crashed with the following message.
Could not cast value of type 'Swift.UInt64' (0x10dddde88) to 'Swift.AnyObject' (0x12129d018).
Please help me. Thanks!
Swift 3 greatly differs from Swift 2.3, when it comes to casting. For example, if you run the following in an Xcode 8 playground (using the latest Swift toolchain, Xcode 8.2 in my case):
import Foundation
import Swift
struct Foo
{
init()
{
}
}
NSStringFromClass(type(of: Foo() as AnyObject))
You will see, that NSStringFromClass(type(of: Foo() as AnyObject)) will register as a "_SwiftValue" in the inspection column on the right.
This is because Swift 3 allows you to wrap any construct as an AnyObject using an internal _SwiftValue class, which can then later be unwrapped in some other part of your code.
Swift 2.3 does not have this feature. That is where you are erring.
But what you can do is cast UInt64 to an NSNumber. This works with both Swift 2.3 and 3.0, if I recall correctly. I realize that you might be dealing with a generic type, and you might not know during compile time whether the type you're dealing with is a UInt64 or something else; but this method should work regardless. You could use the as? operator as well, to handle casting errors and exceptions.
In Swift 2, only Int and UInt are convertible to AnyObject (implicitly or explicitly).
When your explicitly convert Int or UInt to AnyObject, you use as casting, not as!:
//Swift 2.3
let ui: UInt = 1234
let uiObj = ui as AnyObject
let i: Int = 5678
let iObj = i as AnyObject
In fact, they are automatically converted to NSNumber:
//Swift 2.3
print(uiObj.dynamicType) //->__NSCFNumber (__NSCFNumber is one of the concrete subclasses of NSNumber)
print(iObj.dynamicType) //->__NSCFNumber
In Swift 3, some implicit conversions are removed, but since 3.0.1, all integer type can be converted to NSNumber with explicit casting:
//Swift 3.0.2
let ui64: UInt64 = 12345678
let ui64Obj = ui64 as AnyObject
let i8: Int8 = 123
let i8Obj = i8 as AnyObject
let ui: UInt = 1234
let uiObj = ui as AnyObject
let i: Int = 5678
let iObj = i as AnyObject
print(type(of: ui64Obj)) //->_SwiftTypePreservingNSNumber (_SwiftTypePreservingNSNumber is another subclass of NSNumber)
print(type(of: i8Obj)) //->_SwiftTypePreservingNSNumber
print(type(of: uiObj)) //->_SwiftTypePreservingNSNumber
print(type(of: iObj)) //->_SwiftTypePreservingNSNumber
So, if you want to make nearly the same result in Swift 2 as uint64Value as AnyObject in Swift 3, you need to construct NSNumber explicitly.
//Swift 2.3
let ui64: UInt64 = 12345678
let ui64Obj = NSNumber(unsignedLongLong: ui64)
print(ui64Obj.dynamicType) //->__NSCFNumber
Replace uint64Value as AnyObject to NSNumber(unsignedLongLong: uint64Value).
(In fact, _SwiftTypePreservingNSNumber is not exactly the same as __NSCFNumber, but that may not be your problem.)
By the way, when I set Legacy Swift flag to YES in Xcode 8.2, it showed a warning saying:
Swift 2.3 is deprecated and will be removed in a future release of
Xcode. Migrate to Swift 3 now.
Apple is strongly encouraging us to move to Swift 3 immediately.
You'd better hurry migrating your code to Swift 3.

UnsafePointer no longer works in swift 3

After I convert from swift 2 to swift 3, there is an error pop up for the below metioned line
let value = UnsafePointer<UInt32>(array1).pointee
'init' is unavailable: use 'withMemoryRebound(to:capacity:_)' to temporarily view memory as another layout-compatible type.
in swift2 it is like
let value = UnsafePointer<UInt32>(array1).memory
Can someone explain please?
Sorry I'm quite new to swift3
After i have make the changes to
let abc = UnsafePointer<UInt32>(array1).withMemoryRebound(to: <#T##T.Type#>, capacity: <#T##Int#>, <#T##body: (UnsafeMutablePointer<T>) throws -> Result##(UnsafeMutablePointer<T>) throws -> Result#>)
but still what value should go in to the variable? Sorry, i have search around but too bad i can't find a solution
You can try this:
let rawPointer = UnsafeRawPointer(array1)
let pointer = rawPointer.assumingMemoryBound(to: UInt32.self)
let value = pointer.pointee
Raw pointer is a pointer for accessing untype data.
assumingMemoryBound(to:) can convert from an UnsafeRawPointer to UnsafePointer<T>.
Reference :Swift 3.0 Unsafe World
If array is an Array, your best bet is to use withUnsafeBufferPointer:
array.withUnsafeBufferPointer { buffer in
// do something with 'buffer'
// (if you need an UnsafePointer rather than an UnsafeBufferPointer,
// you can access that via the buffer's .baseAddress property)
}
Make sure you don't let the buffer pointer escape from the closure, because it will not be valid outside it.

How do i encode a PersistentID for a song using NSCoder in Swift 3

This is my first time using NSCoder and there used to be a method called encodeInteger but it seems to have vanished in Swift 3 and the docs don't seem to help.
It maybe that the confusion lies in the difference between Int and UInt64. Are they the same?
Should i be using a NSKeyedArchiver and if so how does that work to comply with NSCoding?
Here's before with the error:
And after without an error:
Why don't you use NSNumber and encode it as an object? It'd look like this:
let bigNumber: UInt64 = /* 123 */
let number = NSNumber(value: bigNumber)
// Encoding it just like a String
coder.encode(number, forKey: "BigNumberKey")
// Decoding and using the property uint64Value from NSNumber to get the UInt64 back
if let object = coder.decodeObject(forKey: "BigNumberKey") as? NSNumber {
let decodedBigNumber = object.uint64Value
}
If that's a requirement for some reason, NSCoder supports the encoding of Int64 (and you could cast it, described here).
The change from encodeInteger to just encode is part of SE-0005 (which affected a lot of different classes; UIColor.blueColor() is now UIColor.blue(), for instance).

Swift 2.2 breaks optionals/unwrapping optionals

Swift 2.2 has broken almost all my code. Even this simple string assigning to label doesn't work anymore:
cell.categoryName.text = peopleArray![indexPath.row]["Name"] as? String
The error says "Downcast from 'String?!' to 'String' only unwraps optionals, did you mean to use '!!'?"
What changes do I have to do now.
EDIT:
More Problems:
if (dict["data"]!["DataDetails"] as! NSArray).count == 0 {
}
Due to this I am getting a segmentation fault and the error shows this: warning: cast from 'String?!' to unrelated type 'NSArray' always fails
UPDATE:
I was using NSDictionaries, NSArrays in my classes that seems to cause the problem. Changing all the literals from Obj-C to swift made the code work properly.
So, I will also recommend other developers to prefer swift literals.
it seems there are some slight differences when using the swift types and the objective-c NS... types
eg
let dic:NSDictionary? = ["a":"a"]
let str:NSString? = dic!["a"] as? NSString
let dic2:Dictionary? = ["b":"b"]
let str2:String? = dic2!["b"] //dont need to do any casting, already optional
print(str)
print(str2)
prints
Optional(a)
Optional("b")
so depending on how your array / dictionary is defined, you might need different casting/unwrapping

Resources