'[Task]?' is not convertible to 'Optional<[Any]>' - swift

I've made extension
extension Optional where Wrapped == [Any] {
var isNilOrEmpty: Bool {
get {
if let array = self {
return array.count == 0
} else {
return false
}
}
}
}
Then I try to use it like this
if fetchedResults.fetchedObjects.isNilOrEmpty { ... }
I'm getting error
'[Task]?' is not convertible to 'Optional<[Any]>'
But, by specification
Any can represent an instance of any type at all, including function types.
What is my mistake here?
Task is subclass of NSManagedObject if it matters.

Well, [Task] and [Any] are two different types, and Wrapped == [Any] won't work.
Proper way would be to limit Wrapped by protocol, not specific type.
extension Optional where Wrapped: Collection {
var isNilOrEmpty: Bool {
get { // `get` can be omitted here, btw
if let collection = self {
return collection.isEmpty // Prefer `isEmpty` over `.count == 0`
} else {
return true // If it's `nil` it should return `true` too
}
}
}
}

Related

A way to compare generics in Swift only if they conform to Equatable

Wondering if there's a good way to do this or not:
I have a #propertyWrapper named "Enhanced" that I use. I use the wrappedValue.set to do some actions, and I would also like to do some further actions if the property is Equatable.
Currently, the code looks like this:
#propertyWrapper
class Enhanced<T: Equatable>: Codable
{
private var value: T
var projectedValue: Enhanced<T> { self }
var wrappedValue: T
{
get { value }
set { set(newValue, notify: nil) }
}
func set(_ proposedValue: T, notify: Bool?)
{
let oldValue = value
let newValue = proposedValue
let changed = newValue != oldValue
if changed { /* more magic here */ }
value = newValue
}
}
Now I would like to remove the Equatable conformance over the generic T, but still be able to compare the old and new values IF the generic T conforms to Equatable.
I've tried a handful of techniques, all of which dead end somewhere. My latest was this:
let changed: Bool
switch T.self
{
case let equatableType as any Equatable.Type:
if
let oldEquatableValue = oldValue as? any Equatable,
let newEquatableValue = newValue as? any Equatable
{
changed = newEquatableValue != oldEquatableValue
}
default:
changed = true
}
...but the error is an understandable Binary operator '!=' cannot be applied to two 'any Equatable' operands.
I tried different patterns to cast the generic type T into an Equatable and silently fail if the generic does not conform, but even if they do, the resulting "cast" types I get back aren't equatable themselves.
Any revelations to the proper pattern would be great!
After some deep web-sleuthing, I came across a snippet of code that does the magic I need:
private extension Equatable
{
func isEqualTo(_ rhs: Any) -> Bool
{
if let castRHS = rhs as? Self
{
return self == castRHS
}
else
{
return false
}
}
}
(HT to neonichu/equalizer.swift on GitHub)
With this bit of pseudo type-erasure, I can make this work:
let changed: Bool
if let oldEquatableValue = oldValue as? any Equatable,
let newEquatableValue = newValue as? any Equatable
{
changed = oldEquatableValue.isEqualTo(newEquatableValue) == false
}
else
{
changed = true
}
By using an extension on Equatable that does further casting of the values, this allows for these two values to be compared (and fail if they are not the same).
Hope this helps someone else!

How can I extend append method for Array in optional in Swift?

I am working to make this code works for optional array, but Xcode complain about:
Cannot assign value of type '[Wrapped.Element]' to type 'Wrapped'
Not sure why should be an error?
extension Optional where Wrapped: RangeReplaceableCollection, Wrapped.Element: Equatable {
mutating func customAppend(_ value: Wrapped.Element) {
if (self != nil) {
self?.append(value)
}
else {
self = [value] // Cannot assign value of type '[Wrapped.Element]' to type 'Wrapped'
}
}
}
This will compile:
extension Optional where Wrapped: RangeReplaceableCollection, Wrapped.Element: Equatable {
mutating func customAppend(_ value: Wrapped.Element) {
if (self != nil) {
self?.append(value)
}
else {
self = .init([value]) // <--- RangeReplaceableCollection.init(_ elements:)
}
}
}
This works because RangeReplaceableCollection declares this init:
init<S>(_ elements: S) where S : Sequence, Self.Element == S.Element
So that init is available to any conforming type, and gives the appropriate concrete type.
On the other hand, trying to do self = [value] doesn't work, because that's trying to set self to an Array. But since the extension is on RangeReplaceableCollection, you can't set self to an Array, because that's not its type.
Here is the correct and simplified answer:
extension Optional where Wrapped: RangeReplaceableCollection {
mutating func customAppend(_ value: Wrapped.Element) {
if (self != nil) {
self?.append(value)
}
else {
self = Wrapped([value])
}
}
}

Check if class is equal swift

I have a class where I have an extension to check equality but on test, the equality crashes.
here's my code
extension LPItemAction {
public override func isEqual(_ other: Any?) -> Bool {
if (other as? LPItemAction) == self {
return true
} else if !(other is LPItemAction) {
return false
} else {
let otherAction = other as? LPItemAction
return hash == otherAction?.hash
}
}
}
and my test case is like this
func testIsEqualSelf() {
// Given
let action = LPItemAction()
action.type = .account
// When
let equal = action.isEqual(action)
// Then
XCTAssertTrue(equal)
}
I got a crash with error Thread 1: EXC_BAD_ACCESS (code=2, address=0x16e747fc0)
Since this is obviously a NSObject, you are probably right to override isEqual. There are some rules though.
You cannot use ==. This operator invokes the Equality protocol, which, on NSObject is implemented using isEqual, therefore you end up with infinite recursion.
Another thing is that using hash to compare equality is just wrong.
// test type first
guard let otherAction = other as? LPItemAction else {
return false
}
// test reference equality
if self === otherAction {
return true
}
// test equality of all properties
return type === otherAction.type

Compare / Equatable weak generics in Swift

I want to create an array of weak referenced delegates like so...
fileprivate class WeakDelegate<T:AnyObject> {
weak var value:T?
init (value:T) {
self.value = value
}
}
class Radio {
private var delegates = [WeakDelegate<AnyObject>]()
}
So far so good...? what I'd like to do also is tidy up my array in these two ways...
1.
func removeDeadDelegates() {
let liveDelegates = delegates.filter { $0.value != nil }
delegates = liveDelegates
}
and 2.
func remove<T>(specificDelegate:T) {
let filteredDelegates = delegates.filter { $0.value != specificDelegate }
listeners = filteredDelegates
}
Says Cannot convert value of type 'T' to expected argument type '_OptionalNilComparisonType'
Now I can just add this to make the warning go away like this...
let liveDelegates = delegates.filter {
if let d = specificDelegate as? _OptionalNilComparisonType {
return $0.value != d
}
return true
}
but this cast doesn't work...
I'm concerned because I'm not sure what this means... can anyone explain why I can't compare generics with == and why this cast is failing?
Thanks for your time
EDIT
Like this?
func remove<T:AnyObject>(delegate:T) {
let filteredDelegates = delegates.filter { $0.value != delegate }
delegates = filteredDelegates
}
No joy sadly...
Instances of a class type can be compared with the “identical to”
=== and “not identical to” !== operators:
func remove(specificDelegate: AnyObject) {
let filteredDelegates = delegates.filter { $0.value !== specificDelegate }
delegates = filteredDelegates
}
The same works for a generic method
func remove<T:AnyObject>(specificDelegate: T) {
let filteredDelegates = delegates.filter { $0.value !== specificDelegate }
delegates = filteredDelegates
}
(but I do not yet see the advantage of doing so).

Access to stored properties of a struct from a extension in Swift

I'm trying to implement a Stack struct in Swift and making it comply to Generator and Sequence.
class Stack<T> {
var items:Array<T>
var depth : Int{ return items.count}
init(){
items = Array<T>()
}
func push(elm:T){
items += elm
}
func pop()->T?{
if depth > 0{
return items.removeLast()
}else{
return nil
}
}
}
I get into trouble when trying to make it comply to Generator. I tried adding a nested type through an extension, that's when I get an error:
extension Stack{
struct StackGenerator: Generator{
var current = 0
mutating func next() -> T?{
let rc = items[current] // Get an error here: can't access items in Stack
}
}
}
The compiler won't let me access the Stack.items property form within StackGenerator. Is this to be expected? How can I work around this?
Generic types can't have nested types - you need to either build StackGenerator outside of your Stack declaration, or use the GeneratorOf<T> type in your generate function.
The first option could look like this:
class Stack<T> : SequenceType {
var items: Array<T>
var depth: Int { return items.count }
init(){
items = Array<T>()
}
func push(elm:T){
items += [elm]
}
func pop()->T?{
if depth > 0 {
return items.removeLast()
} else {
return nil
}
}
func generate() -> StackGenerator<T> {
return StackGenerator(stack: self)
}
}
struct StackGenerator<T>: GeneratorType {
typealias Element = T
var current = 0
var stack: Stack<T>
init (stack: Stack<T>) {
self.stack = stack
}
mutating func next() -> T? {
if current < self.stack.items.count {
return self.stack.items[current++] // Get an error here: can't access items in Stack
}
return nil
}
}