Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NSArray: add [safe:] subscripts #1

Open
orchetect opened this issue Jan 17, 2021 · 1 comment
Open

NSArray: add [safe:] subscripts #1

orchetect opened this issue Jan 17, 2021 · 1 comment
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@orchetect
Copy link
Owner

Objective

On NSArray and NSMutableArray, add a custom subscript that duplicates the [safe:] subscript that OTCore already implements on standard Swift collections.

Interface

extension NSArray {
    open subscript(safe index: Int) -> Any? { get }
}

extension NSMutableArray {
    open subscript(safe index: Int) -> Any? { get set }
}

Implementation

  1. The implementation checks that the passed index is safe (it is not out-of-bounds).
  2. If the index is valid, then the element at that index is returned.
  3. If the index is not valid, then nil is returned.

Problem

I could not find a way to make the compiler happy when both subscripts use the same label "safe:". The nature of Objective-C objects is making this elusive to figure out.

The following implementation does function as expected (with unique subscript labels) but the goal is to use the same labels.

extension NSArray {
    open subscript(safe index: Int) -> Any? {
        (0..<count).contains(index) ? self[index] : nil
    }
}

extension NSMutableArray {
    open subscript(safeMutable index: Int) -> Any? {
        get {
            (0..<count).contains(index) ? self[index] : nil
        }
        set {
            guard (0..<count).contains(index) else { return }
            self[index] = newValue!
        }
    }
}

As soon as you make the subscript labels the same, it will not compile.

extension NSArray {
    open subscript(safe index: Int) -> Any? { get }
}

extension NSMutableArray {
    // Compiler Error: "Overriding non-@objc declarations from extensions is not supported"
    open subscript(safe index: Int) -> Any? { get set }
}

However, making both subscripts @objc and having the NSMutableArray declared override will allow the code to compile, but the functions are never actually executed when the subscript is called. Instead, the underlying subscript executes (which of course produces EXC_BAD_INSTRUCTION when an index is out-of-bounds since that is default behavior of NSArray and NSMutableArray.

extension NSArray {
    @objc open subscript(safe index: Int) -> Any? { get }
}

extension NSMutableArray {
    @objc open override subscript(safe index: Int) -> Any? { get set }
}

Next Steps

I believe the goal of implementing this with identical subscript labels [safe:] for both NSArray and NSMutableArray is possible, but it will require more research and assistance.

@orchetect orchetect added enhancement New feature or request help wanted Extra attention is needed labels Jan 17, 2021
@orchetect
Copy link
Owner Author

orchetect commented Jan 21, 2021

Currently, these are implemented in the library as:

NSArray:

let array = NSArray()

let getVal = nsArray[safe: 1]

NSMutableArray:

let array = NSMutableArray()

// both getters work ([safe:] is inherited from NSArray):
let getVal = array[safe: 1]
let getVal = array[safeMutable: 1]

// setter:
array[safeMutable: 1] = newValue

But the goal is to unify them into a single [safe:] subscript for both NSArray (get) and NSMutableArray (get and set).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

1 participant