Creating a time base info struct in C is easy, but in Swift the following does not work in the playground:
let timebaseInfo: mach_timebase_info_data_t = mach_timebase_info(&timebaseInfo)
The error is Variable used within its own initial value
I understand the error, but I am unable to think of a way to do this without dropping down to C. Is there a Swift only way that I am missing? Any help would be greatly appreciated. :-)
Edit: Actually I see "A" problem with the above, the "=" doesn't make sense. But I did try the following also:
let timebaseInfo: mach_timebase_info_data_t
mach_timebase_info(&timebaseInfo)'
With an error stating timebasedInfo used before initialization. :-(
The mach_timebase_info function is declared as
typealias mach_timebase_info_t = UnsafeMutablePointer<mach_timebase_info>
// ...
func mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t
which means that you can pass an (initialized) mach_timebase_info variable
as an "in-out expression" with &:
var timebaseInfo = mach_timebase_info(numer: 0, denom: 0)
let status = mach_timebase_info(&timebaseInfo)
if status == KERN_SUCCESS {
// ...
}
For more information, see Interacting with C APIs in the "Using Swift with Cocoa and Objective-C" manual:
Mutable Pointers
When a function is declared as taking an UnsafeMutablePointer<Type>
argument, it can accept any of the following:
nil, which is passed as a null pointer
An UnsafeMutablePointer<Type> value
An in-out expression whose operand is a stored lvalue of type Type,
which is passed as the address of the lvalue
An in-out [Type] value, which is passed as a pointer to the start of
the array, and lifetime-extended for the duration of the call
You'll need to use UnsafeMutablePointer<Type>, as follows:
let p = UnsafeMutablePointer<mach_timebase_info_data_t>.alloc(1)
mach_timebase_info(&p.memory)
swift 5.5:
let timebaseInfo: mach_timebase_info_data_t = {
let pointer = UnsafeMutablePointer<mach_timebase_info_data_t>.allocate(capacity: 1)
precondition(mach_timebase_info(pointer) == KERN_SUCCESS)
let info = pointer.pointee
defer { pointer.deallocate() }
return info
}()
func convertToNanoseconds(_ value: UInt64) -> UInt64 {
return (value * UInt64(timebaseInfo.numer)) / UInt64(timebaseInfo.denom)
}
Related
struct Payload {}
struct User {}
struct Post {}
protocol Mapper {
associatedtype PayloadType
associatedtype ResultType
func map(_ payload: PayloadType) -> ResultType
}
class AnyMapper<P, R>: Mapper {
private var _mapClouser: (P) -> R
init<M: Mapper>(_ mapper: M) where M.PayloadType == P, M.ResultType == R {
_mapClouser = mapper.map(_:)
}
func map(_ payload: P) -> R {
_mapClouser(payload)
}
}
class UserMapper: Mapper {
func map(_ payload: Payload) -> User {
return User()
}
}
class PostsMapper: Mapper {
func map(_ payload: Payload) -> [Post] {
return [Post(), Post(), Post()]
}
}
let userMapper = AnyMapper(UserMapper())
let postsMapper = AnyMapper(PostsMapper())
var array: [AnyMapper] = [userMapper, postsMapper] <<< Error: Cannot convert value of type 'AnyMapper<Payload, [Post]>' to expected element type 'AnyMapper<Payload, User>'
I tried to put 2 objects into array, but I get this error: Cannot convert value of type 'AnyMapper<Payload, [Post]>' to expected element type 'AnyMapper<Payload, User>'
Can someone explain to me how to fix it?
AnyMapper by itself is not a type. It is a type constructor. Essentially, it is a “function” that
runs at compile time,
takes types as arguments named P and R, and
returns a type.
So for example if you say AnyMapper<Payload, User>, that's a compile-time function call to the type constructor AnyMapper, passing the arguments Payload and User. It returns a type, which we just refer to using the same syntax, AnyMapper<Payload, User>.
Often, Swift can deduce the argument types, so although you don't pass them explicitly, Swift passes them for you.
That's what's happening on these two lines:
let userMapper = AnyMapper(UserMapper())
let postsMapper = AnyMapper(PostsMapper())
Each of those lines “calls“ AnyMapper after deducing the P and R arguments. We can make the P and R arguments explicit, and also make the returned types explicit, like this:
let userMapper: AnyMapper<Payload, User> = AnyMapper<Payload, User>(UserMapper())
let postsMapper: AnyMapper<Payload, [Post]> = AnyMapper<Payload, [Post]>(PostsMapper())
So now we can see that you're creating two objects of two different types.
You next write this:
var array: [AnyMapper] = [userMapper, postsMapper]
Since you're not explicitly passing type arguments to AnyMapper, you're asking Swift to deduce the arguments. It does so by looking at the first element of the array literal, userMapper. Based on that, it deduces P = Payload and R = User, so it acts like you wrote this:
var array: [AnyMapper<Payload, User>] = [userMapper, postsMapper]
But postsMapper is not an AnyMapper<Payload, User>, so Swift can't compile that statement.
What all this means is that AnyMapper erases only the wrapped Mapper's specific type, but not its PayloadType and ResultType associated types.
It's not clear why you would want to put userMapper and postsMapper in the same array anyway. They have different result types, so you wouldn't be able to treat their results generically. Perhaps if you explain why you think you need to put them both in a single array, we can give you better guidance.
[Post] and User are not the same type. You don't need an erasing type to put them into the same array.
var array: [any Mapper] = [UserMapper(), PostsMapper()]
In Swift, I have a function that I am passing an array to, and then using that array in another function. I keep getting this error:
Cannot convert value of type 'Array[String]' to expected argument type 'Set<String>'
#objc func getProductInfo(productIDs: Array<String>) -> Void {
print(productIDs) //this works with correct data
SwiftyStoreKit.retrieveProductsInfo(productIDs) { result in
...
The rest works, and is tested when I pass in a regular array of ["Monthly", "Yearly", "etc..."].
["Monthly", "Yearly", "etc..."] is not an array, it's an array literal. Set can be implicitly initialized with an array literal.
let ayeSet: Set<String> = ["a"] // Compiles
But, it cannot be implicitly initialized with an array.
let bees: Array<String> = ["b"]
let beeSet: Set<String> = bees // Causes Compiler Error
However, if you explicitly initialize it, then it will work.
let sees: Array<String> = ["c"]
let seeSet: Set<String> = Set(sees) // Compiles
So, in your example explicitly initialization should work.
#objc func getProductInfo(productIDs: Array<String>) -> Void {
print(productIDs) //this works with correct data
SwiftyStoreKit.retrieveProductsInfo(Set(productIDs)) { result in
...
You just need to change you method parameter type. SwiftyStoreKit method is expecting a String Set. Your method declaration should be:
func getProductInfo(productIDs: Set<String>)
I've face the issue using the same lib.
This should work
SwiftyStoreKit.retrieveProductsInfo(Set(productIDs))
I have the following C struct:
typedef struct {
char** categories;
int category_size;
} category_fmc_s_type;
My Swift array has the following values:
let categories = ["Weekday", "Weekend"]
I want to populate the C Struct field 'categories' with 'Weekday' & 'Weekend'. To do this I call my toPointer():
fileprivate static func toPointer(_ args: [String]) -> UnsafeMutablePointer<UnsafeMutablePointer<Int8>> {
let buffer = UnsafeMutablePointer<UnsafeMutablePointer<Int8>>.allocate(capacity: args.count)
for (index, value) in args.enumerated() {
buffer[index] = UnsafeMutablePointer<Int8>(mutating: (value as NSString).utf8String!)
}
return buffer
}
I keep getting the following XCode 8 error:
Cannot convert value of type 'UnsafeMutablePointer<UnsafeMutablePointer<Int8>>' to expected argument type 'UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!'
Any suggestions? I don't understand why there is the optional and '!' in the C-Struct definition implicitly.
As the compiler emits as an error, you need to unwrap after Int8 w/ "?" as follows.
fileprivate func toPointer(_ args: [String]) -> UnsafeMutablePointer<UnsafeMutablePointer<Int8>?> {
let buffer = UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>.allocate(capacity: args.count)
for (index, value) in args.enumerated() {
buffer[index] = UnsafeMutablePointer<Int8>(mutating: (value as NSString).utf8String!)
}
return buffer
}
then,
func testMyCat() {
let categories = ["Weekday", "Weekend"]
let buffer = toPointer(categories)
var mycat = category_fmc_s_type()
mycat.categories = buffer // you would see compile error w/o "?"
}
the code above works w/o error. Martin's solution gives a compile error at
mycat.categories = &cargs (see the link)
I don't know why.
Check the reference of utf8String property of NSString:
Discussion
This C string is a pointer to a structure inside the string object,
which may have a lifetime shorter than the string object and will
certainly not have a longer lifetime. Therefore, you should copy the
C string if it needs to be stored outside of the memory context in
which you use this property.
The term memory context is not well-defined, but one thing sure is that you cannot expect the allocated region for the C string would live forever. When the member categories in the category_fmc_s_type is accessed, the pointers may be pointing to the already freed regions.
Applying the suggestion from Martin R to your code, your code would be like this:
fileprivate static func toPointer(_ args: [String]) -> UnsafeMutablePointer<UnsafeMutablePointer<Int8>?> {
let buffer = UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>.allocate(capacity: args.count)
buffer.initialize(from: args.lazy.map{strdup($0)})
return buffer
}
And remember, after you finish using the category_fmc_s_type, you need to deallocate the regions allocated by strdup(_:) and UnsafeMutablePointer.allocate(capacity:):
fileprivate static func freePointer(_ pointers: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>, count: Int) {
for i in 0..<count {
free(pointers[i])
}
pointers.deinitialize(count: count)
pointers.deallocate(capacity: count)
}
import Foundation
func insertionSort<T where T: Comparable>(var items:[T])-> [T] {
for (index, _) in items.enumerate().dropFirst() {
var j = index
while ((j > 0) && (items[j] < items[j-1])) {
swap(&items[j], &items[j-1])
j = j-1
}
}
return items
}
// Test the function
insertionSort([]) // Generic type array is not taking empty array
When I am trying to call insertionSort with empty array, I get
Cannot invoke 'insertionSort' with an argument list of type '([_])'
I am not able to figure out how to fix this.
To call generic functions in Swift, Swift needs to be able to infer the generic parameters.
One way giving the type information to Swift, is using an intermediate variable.
(Like noted in Lu_'s comment.)
let arr: [Int] = []
let result = insertionSort(arr)
Another way is using as.
let result = insertionSort([] as [Int])
(Remember, var parameter does not modify the actual argument. It just makes a mutable copy, but does not write it back to the original argument. Swift 3 removed var parameters, as it's so confusing. You may need to assign the return value of the function to a variable.)
In Swift I declared a function that differs from Array.count only in that if array == nil the function returns 0. This is related to my UITableViewDataSource, but that's not important here. The problem is, if I declare the function as:
class func countOfItemsInArray(array: [AnyObject]?) -> Int
and then try to pass it an array of structs, it declares that the structs in the array do not conform to AnyObject. I understand why that is (I think), but is there a way to make this work with classes and structs, or should I just give in to copy and paste?
Generics are probably better suited to this problem than relying on covariance of [AnyObject]. A version of countElements that worked on an optional array and returned 0 in case of nil could go like this:
func countElements<T>(array: [T]?) -> Int {
return array?.count ?? 0
}
When you call countElements with any kind of array, the placeholder T is replaced with the type of the element contained in the array.
Note, this version overloads the existing countElements with a version that takes an optional. If you call it with a non-optional or any other kind of collection, the Swift version would be called, if you pass in an optional array, this one will be called. It’s debatable whether this is a good practice (I think it’s fine) or a bad one (some may disapprove :).
A version that works on any collection type would be:
func countElements<C: CollectionType>(col: C?) -> C.Index.Distance {
return col.map { countElements($0) } ?? 0
}
If you use Any instead of AnyObject you can pass any type, so also structs:
class func countOfItemsInArray(array: [Any]?) -> Int
This is kind of weird.
I used this function:
func countOfItemsInArray(array: [Any]?) -> Int {
return array != nil ? array!.count : 0
}
Declared two of your Assignment structs and put them in an array:
let structOne = Assignment(name: "1", dueDate: NSDate(), subject: "1")
let structTwo = Assignment(name: "2", dueDate: NSDate(), subject: "2")
let myArray: [Assignment] = [structOne, structTwo]
But here's the interesting part.
When calling println(countOfItemsInArray(myArray)) it gives the error:
<stdin>:27:33: error: 'Assignment' is not identical to 'Any'
println(countOfItemsInArray(myArray))
^
<stdin>:17:26: note: in initialization of parameter 'array'
func countOfItemsInArray(array: [Any]?) -> Int {
^
So I tested if myArray is of type [Any]:
println(myArray is [Any])
to which swift says:
<stdin>:25:17: error: 'Any' is not a subtype of 'Assignment'
println(myArray is [Any])
^
But when I change the type annotation of myArray to [Any] it works:
let myArray: [Any] = [structOne, structTwo]
And when simply handing the literal to the function it works, too:
countOfItemsInArray([structOne, structTwo])
The whole code example can be seen here.