Swift access to variable length array
You can create a buffer pointer that starts at the given address and has the given
number of elements:
let buffers = UnsafeBufferPointer<AudioBuffer>(start: &bufferList.memory.mBuffers,
count: Int(bufferList.memory.mNumberBuffers))
for buf in buffers {
// ...
}
Update for Swift 3 (and later):
let buffers = UnsafeBufferPointer<AudioBuffer>(start: &bufferList.pointee.mBuffers,
count: Int(bufferList.pointee.mNumberBuffers))
for buf in buffers {
// ...
}
How to access in Swift a C struct that contains a variable sized array?
Zero-length arrays in C are not visible in Swift. A possible workaround is to add a helper function in the bridging header file, which returns the address of the first array item:
static uint32_t * _Nonnull idArrayPtr(const IDListPtr _Nonnull ptr) { return &ptr->idArray[0]; }
Now you can create a “buffer pointer” in Swift which references the variable length array:
let idListPtr = getIDList()
let idArray = UnsafeBufferPointer(start: idArrayPtr(idListPtr), count: Int(idListPtr.pointee.count))
for item in idArray {
print(item)
}
Tuple-Array with variable content types & length?
A tuple is inappropriate because you cannot declare a tuple in a generic manner.
A possible solution is to declare data
as an array of CustomStringConvertible
instead of a tuple.
The benefit is you can pass any type which supports String Interpolation and the number of items in the array is variable.
func debugData(names: [String], data: [[CustomStringConvertible]] ) {
var debugLine = ""
for line in data {
for i in 0..<line.count {
debugLine += "\(names[i])=\(line[i]) "
}
print(debugLine)
debugLine = ""
}
}
debugData(names: ["Name", "Age", "SexM"], data: [["Alex", 5, true], ["Lisa", 7, false], ["Max", 9, true]])
Parse json file with variable length in Swift
Rather than having a CoinData
struct, you can decode a dictionary with the cryptocurrencies' names as the keys, and Price
objects as the values.
let coinData = try decoder.decode([String: Price].self, from: data!)
Now to get the Price
for Bitcoin for example, you can just do:
if let bitcoinPrice = coinData["bitcoin"] {
// ...
} else {
// there is no price info about bitcoin in the JSON!
}
In Swift, how to get the true size of an `Any` variable?
I'll begin with some technical details about the limitations of Any
in this case.
So, what is Any
? It's an empty protocol to which every type implicitly conforms to.
And how does the compiler represent variables of protocol types? It's by wrapping the actual value in an existential container. So basically when you're referencing a variable of this kind, you're actually talking to the container (well, actually not you, but the compiler is :).
An existential container has a layout that can be represented like this C structure:
struct OpaqueExistentialContainer {
void *fixedSizeBuffer[3];
Metadata *type;
WitnessTable *witnessTables[NUM_WITNESS_TABLES];
};
The container elements are greatly explained in this document, I'll also try to summarize them here:
fixedSizeBuffer
either holds the whole value, if it takes less than 24 bytes, or holds a pointer to a heap allocated zone, containing the valuetype
is a pointer to the type metadatawitnessTables
is what makes this layout occupy various sizes, as the number of protocol witness tables can vary from zero to virtually any number of protocols.
So, with the above in mind:
Any
needs no witness tables, thus it occupies 32 bytes- a single protocol variable occupies 40 byes
- a composed protocol variable occupies 32 + N*8, where N is the number of "independent" protocols involved in the composition
Note that the above is true if there are no class protocols involved, if a class protocol is involved, then the existential container layout is a little bit simplified, this is also better described in the linked document from above.
Now, back to the problem from the question, it's the existential container created by the compiler the one which prevents you from accessing the actual type. The compiler doesn't make this structure available, and transparently translates any calls to protocol requirements to dispatches through the witness tables stored in the container.
But, might I ask you, why are you circulating Any
? I assume you don't want to handle all possible and future types in a generic manner. A marker protocol might help here:
protocol MemoryLayouted { }
extension MemoryLayouted {
var memoryLayoutSize: Int { MemoryLayout.size(ofValue: self) }
}
Then all you have left to do is to add conformance for the types you want to support:
extension Int: MemoryLayouted { }
extension String: MemoryLayouted { }
extension MyAwesomeType: MemoryLayouted { }
With the above in mind, you can rewrite your initial code to something like this:
let regularInt: Int = 1
let anyInt: MemoryLayouted = 2
print(regularInt.memoryLayoutSize) // 8
print(anyInt.memoryLayoutSize) // 8
You get consistent behaviour and type safety, a type safety that might translate to a more stable application.
P.S. A hacky approach, that allows you to use Any
, might pe possible by unpacking the existential container via direct memory access. The Swift ABI is stable at this point, so the existential container layout is guaranteed not to change in the future, however not recommending going that route unless absolutely necessary.
Maybe someone that stumbles this question and has experience in the ABI layout code can provide the code for it.
How to create a fixed-size array of objects
Fixed-length arrays are not yet supported. What does that actually mean? Not that you can't create an array of n
many things — obviously you can just do let a = [ 1, 2, 3 ]
to get an array of three Int
s. It means simply that array size is not something that you can declare as type information.
If you want an array of nil
s, you'll first need an array of an optional type — [SKSpriteNode?]
, not [SKSpriteNode]
— if you declare a variable of non-optional type, whether it's an array or a single value, it cannot be nil
. (Also note that [SKSpriteNode?]
is different from [SKSpriteNode]?
... you want an array of optionals, not an optional array.)
Swift is very explicit by design about requiring that variables be initialized, because assumptions about the content of uninitialized references are one of the ways that programs in C (and some other languages) can become buggy. So, you need to explicitly ask for an [SKSpriteNode?]
array that contains 64 nil
s:
var sprites = [SKSpriteNode?](repeating: nil, count: 64)
This actually returns a [SKSpriteNode?]?
, though: an optional array of optional sprites. (A bit odd, since init(count:,repeatedValue:)
shouldn't be able to return nil.) To work with the array, you'll need to unwrap it. There's a few ways to do that, but in this case I'd favor optional binding syntax:
if var sprites = [SKSpriteNode?](repeating: nil, count: 64){
sprites[0] = pawnSprite
}
Is there a way to declare an arbitrary number of arrays in Swift?
Use an array of arrays, as jnpdx says in their comment.
let ballot1 = ["candidateB", "candidateA", "candidateD"]
let ballot2 = ["candidateC", "candidateD"]
let ballots = [ballot1, ballot2]
or just
let ballots = [["candidateB", "candidateA", "candidateD"],
["candidateC", "candidateD"]]
Then you can refer to your ballots using indexes:
ballots[0]
would give you an array of candidates for the first ballot, or you could loop through the outer array:
for (index, ballot) in ballots.enumerated() {
print("Ballot \(index+1) has candidates \(ballot[index])")
}
Note that you might want to make each ballot a struct, with fields for a title, the array of candidates, and any other information you might want. Then you could have an array of ballot structs:
struct Ballot {
let title: String
let description: String? // Optional field
let candidates: [String]
}
And then:
let ballots = [Ballot(title: "5th congressional district",
description: nil,
candidates: ["Joe", "Briana", "Jamal", "Ivan"]),
Ballot(title: "Mayor",
description: nil,
candidates: ["Adrienne", "Moisha", "Dave", "Demtri"])
]
And:
for aBallot in ballots {
print("Ballot titled \(aBallot.title) has candidates \(aBallot.candidates)")
Swift use sizeof with Int32 Array
You can get the number of elements in an array simply with
let count = testArray.count
and the total number of bytes of its elements with
var arrayLength = testArray.count * sizeof(Int32)
// Swift 3:
var arrayLength = testArray.count * MemoryLayout<Int32>.size
sizeof
is used with types and sizeofValue
with values, so both
var arrayLength = sizeof([Int32])
var arrayLength = sizeofValue(testArray)
would compile. But that gives you the size of the struct Array
, not the size
of the element storage.
Swift Global Variables
You shouldn't use global variables, I don't think that's recommended in any language.
Now here you have what looks like a Singleton class (BroadService), that's good because it's a nice solution for what you're looking for.
Next all you need to do is add a property to that class. Let's say videoLink
is a string, you can add a string property to BroadService
, for example storedVideoLink
as an optional String, and the next time you need to obtain that value after you have already fetched it, you can access it like so: BroadService.sharedInstance.storedVideoLink
.
One more thing, to have BroadService
work properly as a singleton, you should make its init
private.
To sum up, here's what I'm suggesting:
class BroadService {
static let sharedInstance = BroadService()
var storedVideoLink: String?
private init() {} // to ensure only this class can init itself
func fetchBroadcasts(completion: @escaping ([Games]?) -> ()) {
// your code here
}
}
// somewhere else in your code:
BroadService.sharedInstance.fetchBroadcasts { (games) in
if let games = games {
let game = games[indexPath]
let videoLink = game.videoLink
BroadService.sharedInstance.storedVideoLink = videoLink
}
}
// now you can access it from anywhere as
// BroadService.sharedInstance.storedVideoLink
This way it all stays cohesive in the same class. You can even add a getter method for storedVideoLink
so you don't have to access it directly, and in this method you could state that if the string is nil then you fetch the data, store the link to the string, and then return the string.
Related Topics
Swiftui - in Sheet Have a Fixed Continue Button That Is Not Scrollable
Swift/Firebase - Sort Posts in Tableview by Date
Retrieve Multiple Photos Under a Node from Firebase Storage
Nsimage Getting Resized When I Draw Text on It
Difference Between Nsrange and Nsmakerange
Making Parts of Text Bold in Swiftui
Swift Task Continuation Misuse: Leaked Its Continuation - for Delegate
Why Do Integers Not Conform to the Anyobject Protocol
Possible to Pass an Enum Type Name as an Argument in Swift
Add Constraints to Generic Parameters in Extension
If the Swift 'Guard' Statement Must Exit Scope, What Is the Definition of Scope
Print the Nstableview's Row Number of the Row Clicked by the User