In Swift, can I write a generic function to resize an array?
The most generic method...
Array
adaptsRangeReplaceableCollection
protocol which include methods which can help resizing. (No need to use a loop)You need to construct new instances of the element when you grow the array. So you either provide a default value...
extension RangeReplaceableCollection {
public mutating func resize(_ size: IndexDistance, fillWith value: Iterator.Element) {
let c = count
if c < size {
append(contentsOf: repeatElement(value, count: c.distance(to: size)))
} else if c > size {
let newEnd = index(startIndex, offsetBy: size)
removeSubrange(newEnd ..< endIndex)
}
}
}
var f = ["a", "b"]
f.resize(5, fillWith: "") // ["a", "b", "", "", ""]
f.resize(1, fillWith: "") // ["a"]
- or you create a protocol that provides the default value
init()
. Note that you need to manually adapt the protocol to every types you care about.
public protocol DefaultConstructible {
init()
}
extension String: DefaultConstructible {}
extension Int: DefaultConstructible {}
// and so on...
extension RangeReplaceableCollection where Iterator.Element: DefaultConstructible {
public mutating func resize(_ size: IndexDistance) {
resize(size, fillWith: Iterator.Element())
}
}
var g = ["a", "b"]
g.resize(5)
g.resize(1)
Array of generic type as argument to function
You need to supply the generic type of the class Event. The following code compiles correctly:
Event<Int>.listenAny(l, events: v)
Note: I use Int as the generic type, but you can use any type.
Functions on generic arrays
You want to cast the tuple Array
of type [(index: Int, value: T)]
where T
is of type Reminder
to a tuple Array
of type [(index: Int, reminder: Reminder)]
. So you can see that the tuples have different element names (value and reminder) where both have different byte sizes - therefore the error.
So you should take the same element names for both tuples.
If you want to change the element names:
let newTupleArray = oldTupleArray.map{ (newElementName0: $0.0, newElementName1: $0.1) }
Functions on generic arrays
You want to cast the tuple Array
of type [(index: Int, value: T)]
where T
is of type Reminder
to a tuple Array
of type [(index: Int, reminder: Reminder)]
. So you can see that the tuples have different element names (value and reminder) where both have different byte sizes - therefore the error.
So you should take the same element names for both tuples.
If you want to change the element names:
let newTupleArray = oldTupleArray.map{ (newElementName0: $0.0, newElementName1: $0.1) }
Swift array of mixed generic types
No need to explicitly type:
class Test<T, U> {
init(key: T, value: U) {
}
}
let array: [Test<String, Any>] = [
Test(key: "test", value: []),
Test(key: "test", value: 42)
]
Update:
typealias tuple = (Any,Any)
class TestBlock
{
let key: String
let block: (tuple) -> Void
init(key: String, block: @escaping (tuple) -> Void)
{
self.key = key
self.block = block
}
}
let block1: (tuple) -> Void = { (arg) in
let (_label, _size) = arg
let label = _label as! UILabel
label.font = label.font.withSize((_size as! CGFloat))
}
let block2: (tuple) -> Void = { (arg) in
let (_label, _color) = arg
let label = _label as! UILabel
let color = _color as! UIColor
label.textColor = color
}
let propertiesWithBlock: [TestBlock] = [
TestBlock(key: "fontSize", block: block1),
TestBlock(key: "textColor", block: block2)
]
Swift generics and subclasses
One approach is to iterate over the array and use optional binding
to check if an element is of the given type:
func getFirst<T: MyClass>(ofType: T.Type) -> T? {
for elem in values {
if let item = elem as? T {
return item
}
}
return nil
}
This can be simplified using for case
with the as
pattern:
func getFirst<T: MyClass>(ofType: T.Type) -> T? {
for case let item as T in values {
return item
}
return nil
}
Another approach is to use flatMap
to find all items of the given
type and return the first one:
func getFirst<T: MyClass>(ofType: T.Type) -> T? {
return values.flatMap { $0 as? T }.first
}
If the array can be large and you want to avoid the creation of an
intermediate array then you can use lazy
:
func getFirst<T: MyClass>(ofType: T.Type) -> T? {
return values.lazy.flatMap { $0 as? T }.first
}
As an array extension method this would be
extension Array {
func getFirst<T>(ofType: T.Type) -> T? {
return flatMap { $0 as? T }.first
}
}
reserveCapacity(Swift) vs resize(C++)
You're confusing the underlying storage of the array from the actual size of the array.
Arrays in Swift are dynamic, so you can append()
and the array will grow in size accordingly.
Internally, Swift manages how the underlying memory is allocated for you, so you don't need to think about it.
When you reserveCapacity
, this is telling Swift you anticipate that the array will be of this size eventually so it should get the memory ready for you in advance.
It's essentially just a performance optimization that you don't normally need to make, unless you know an array will grow to a given size eventually.
This does not mean the array now has this memory initialized with values, so accessing an element out-of-bounds will cause a crash.
If you want an array that is pre-initialized with values, you can use the init(repeating:count:)
initializer like so:
var arr = Array(repeating: 0, count: 10000)
This will both allocate storage for 10,000 elements and initialize each value to 0
, so now you can access any index in this range safely.
Swift: Make function universal using generics?
Why you think you need generics here? Here how I see your function:
func open(inout theSwitch: Bool, array: [UIView]) {
for item in array {
item.hidden = !theSwitch
}
theSwitch = !theSwitch
}
Usage:
var theSwitch = true
var array = [UIButton]()
var mixedViewsArray = [UIButton(), UILabel(), UIView()]
// switch time:
open(&theSwitch, array: array)
open(&theSwitch, array: mixedViewsArray)
You don't need to use reference to original array, since you only change properties in objects in that array, so you only use references from it. open
function will work with any subclass of UIView
class, like UIButton
or UITableViewCell
(you don't even need cast mixedViewsArray
to proper type, its already [UIView]
).
Related Topics
How to Display Image from a Url in Swiftui
Why Is 'Throws' Not Type Safe in Swift
How to Make a Swift Enum with Associated Values Equatable
Environmentobject VS Singleton in Swiftui
How to Change the Z Index or Stack Order of Uiview
Swift: How to Get Everything After a Certain Set of Characters
Xcode 12 Beta and iOS 14: Weird Console Logs "Objc[5551]: Class ... Is Implemented in Both"
Swift, How to Implement Hashable Protocol Based on Object Reference
Singleton and Init with Parameter
How to Go from Cmutablepointer<Cgfloat> to Cgfloat[] in Swift
Fill Circle with Wave Animation in Swiftui
How to Change the Current Day's Hours and Minutes in Swift
How to Disable User Interaction on Swiftui View
Differencebetween Final Class and Class
Uiview Background Color in Swift
Get "Does Not Implement Methodsignatureforselector" When Try to Store Array in Nsuserdefaults,Swift