Does _ArrayType or _ArrayProtocol not available in Swift 3.1?
Type names starting with an underscore should always treated as internal.
In Swift 3.1, it is marked as internal
in the source code and therefore
not publicly visible.
Using _ArrayProtocol
was a workaround in earlier Swift versions where
you could not define an Array
extension with a "same type" requirement.
This is now possible as of Swift 3.1, as described in the
Xcode 8.3 release notes:
Constrained extensions allow same-type constraints between generic parameters and concrete types. (SR-1009)
Using the internal protocol is therefore not necessary anymore,
and you can simply define
extension Array where Element == UInt8 {
}
But note that your static func stringValue()
does not need any
restriction of the element type. What you perhaps intended is to
define an instance method like this:
extension Array where Element == UInt8 {
func stringValue() -> String {
return String(cString: self)
}
}
print([65, 66, 67, 0].stringValue()) // ABC
Also note that String(cString:)
expects a null-terminated sequence
of UTF-8 bytes.
How can I make a extension for array of specific type in Swift
for say the specific type is S
extension CollectionType where Generator.Element == S {
}
CollectionType Protocol
Usage of protocols as array types and function parameters in swift
As of Swift 5.7 / Xcode 14 this can now elegantly be solved using any
.
protocol SomeProtocol: Equatable {
func bla()
}
class SomeClass {
var protocols = [any SomeProtocol]()
func addElement(element: any SomeProtocol) {
protocols.append(element)
}
func removeElement(element: any SomeProtocol) {
if let index = find(protocols, element) {
protocols.remove(at: index)
}
}
}
Array of protocol type
What you need to do is to use type erasure, much like AnyHashable
does in the Swift Standard Library.
You can't do:
var a: [Hashable] = [5, "Yo"]
// error: protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements
What you have to do is to use the type-erased type AnyHashable
:
var a: [AnyHashable] = [AnyHashable(5), AnyHashable("Yo")]
a[0].hashValue // => shows 5 in a playground
So your solution would be to first split the protocol in smaller parts and promote Equatable
to Hashable
(to reuse AnyHashable
)
protocol Conditionable {
var condition: Condition? { get set }
}
protocol Executable {
func execute() -> SKAction
}
protocol Commandable: Hashable, Executable, Conditionable {}
Then create an AnyCommandable
struct, like this:
struct AnyCommandable: Commandable, Equatable {
var exeBase: Executable
var condBase: Conditionable
var eqBase: AnyHashable
init<T: Commandable>(_ commandable: T) where T : Equatable {
self.condBase = commandable
self.exeBase = commandable
self.eqBase = AnyHashable(commandable)
}
var condition: Condition? {
get {
return condBase.condition
}
set {
condBase.condition = condition
}
}
var hashValue: Int {
return eqBase.hashValue
}
func execute() -> SKAction {
return exeBase.execute()
}
public static func ==(lhs: AnyCommandable, rhs: AnyCommandable) -> Bool {
return lhs.eqBase == rhs.eqBase
}
}
And then you can use it like this:
var a = FunctionCommand()
a.commands = [AnyCommandable(MoveCommand()), AnyCommandable(FunctionCommand())]
And you can easily access properties of commands
, because AnyCommandable
implements Commandable
a.commands[0].condition
You need to remember to now add Hashable
and Equatable
to all your commands.
I used those implementations for testing:
struct MoveCommand: Commandable {
var movingVector: CGVector!
var condition: Condition?
func execute() -> SKAction {
return SKAction()
}
var hashValue: Int {
return Int(movingVector.dx) * Int(movingVector.dy)
}
public static func ==(lhs: MoveCommand, rhs: MoveCommand) -> Bool {
return lhs.movingVector == rhs.movingVector
}
}
struct FunctionCommand: Commandable {
var commands = [AnyCommandable]()
var condition: Condition?
func execute() -> SKAction {
return SKAction.group(commands.map { $0.execute() })
}
var hashValue: Int {
return commands.count
}
public static func ==(lhs: FunctionCommand, rhs: FunctionCommand) -> Bool {
return lhs.commands == rhs.commands
}
}
Difference between various type of Variable declaration in swift
Array
is a swift type where as NSArray
is an objective C type. NS classes support dynamic-dispatch and technically are slightly slower to access than pure swift classes.
1) var arr = NSArray()
arr
is an NSArray()
here - you can re-assign things to arr
but you can't change the contents of the NSArray()
- this is a bad choice to use IMO because you've put an unusable array into the variable. I really can't think of a reason you would want to make this call.
2) var arr = NSMutableArray()
Here you have something usable. because the array is mutable you can add and remove items from it
3) var arr = Array()
This won't compile - but var arr = Array<Int>()
will.
Array takes a generic element type ( as seen below)
public struct Array<Element> : CollectionType, MutableCollectionType, _DestructorSafeContainer {
/// Always zero, which is the index of the first element when non-empty.
public var startIndex: Int { get }
/// A "past-the-end" element index; the successor of the last valid
/// subscript argument.
public var endIndex: Int { get }
public subscript (index: Int) -> Element
public subscript (subRange: Range<Int>) -> ArraySlice<Element>
}
4) var arr : NSMutableArray?
You are defining an optional array here. This means that arr
starts out with a value of nil
and you an assign an array to it if you want later - or just keep it as nil. The advantage here is that in your class/struct you won't actually have to set a value for arr
in your initializer
5) var arr : NSMutableArray = []
It sounds like you are hung up on confusion about Optional values.
Optional means it could be nil or it could not
When you type something as type?
that means it is nil
unless you assign it something, and as such you have to unwrap it to access the values and work with it.
Can I use a protocol array in ForEach?
Ok, let's make it work.
The issue
In your case, the compiler expects parameter \.self
to be Hashable
and this parameter is an object of your protocol GalleryItem
.
The solution
To solve this, we can add a requirement to the protocol that can provide an \.id
. For example:
protocol GalleryItem {
func toView() -> AnyView
var id: Int { get } // could be any `Hashable` type
}
And then, instead of using \.self
in the ForEach as identifier, we can use \.id
as an identifier:
ForEach(items, id: \.id) { item in
item.toView()
}
The naming and the type here are pretty much up to you. \.id
and Int
are used as an example.
Related Topics
Differences Between Ways of Initializing a Dictionary
How to Decrease a Value Using Fieldvalue in Firestore (Swift)
How to Make Struct Lazylist in Swiftui
Hiding Dividers in Nssplitview
Xcode 7.1 Beta: Content of File Error
How to Handle Async Requests in Swift
Swift - Protocol as Type as Target of Button Action
Xcode 8.0 Cbcentralmanager Issue
Swift Accessing Response from Function
Check If on Correct Dispatch Queue in Swift 3
Setting Title of Uinavigationbar Not Working
Expanding Uitextview Inside a Stack View with Scrolling Enabled
Arkit Setting Worldtrackingconfiguration to Gravityandheading Produces Error
Swift 2.2 Decrementing Specific for Loop in Swift 3