2014-12-17 2 views
6

Я пытаюсь создать подкласс NSMutableArray в Swift, который поддерживает инициализатор литерала массива.Создание подкласса NSMutabaleArray в Swift

я могу создать простой подкласс:

class MyArray: NSMutableArray { 
} 

И инициализация работает отлично:

let arrayInstance: MyArray = MyArray() 

Однако, если я пытаюсь использовать массив литерал:

let arrayInstance: MyArray = ["one"] 

Он терпит неудачу во время выполнения, [NSMutableArray initWithCapacity:]: method only defined for abstract class..

Я могу добавить Инициализатора, однако, в результате я также добавить другие необходимые инициализаторов:

class MyArray: NSMutableArray { 
    override init(capacity numItems: Int) { 
    super.init(capacity: numItems) 
    } 

    required init(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    required convenience init(arrayLiteral elements: AnyObject...) { 
     fatalError("init(arrayLiteral:) has not been implemented") 
    } 
} 

К сожалению, вторая необходимая инициализатора дает следующее сообщение об ошибке компилятора:

Declarations from extensions cannot be overridden yet

Похоже, я застрял! Может ли кто-нибудь предложить способ создания подкласса NSMutableArray, который поддерживает литералы массивов? В противном случае он вернется к Objective-C для меня!

+1

Почему именно вам нужно подкласс класса? Почему вы не используете массивы Swift? – Teejay

+2

Вы правы, что это, вероятно, невозможно сделать в Swift из-за того, как реализуется «NSMutableArray» (нужный init из категории «NSArrayCreation», а не для самого класса). Если бы вы были кем-то еще, я бы прочитал лекцию о кластерах классов без подкласса, если вы не знаете, что делаете (а затем все еще не делаете этого, потому что это сумасшедшая и всегда головная боль), но в вашем случае я предполагаю, что вы знаете, что , и поэтому мне просто интересно, почему вы подклассифицируете 'NSMutableArray'. –

+2

@RobNapier, это очень хороший общий совет! Причина, по которой я подклассифицирую «NSMutableArray», заключается в том, что я хочу, чтобы массив наблюдался (как в шаблоне наблюдателя). Ранее я использовал это в Objective-C, чтобы упростить привязку динамических данных к табличным представлениям (http://www.scottlogic.com/blog/2014/11/04/mutable-array-binding-reactivecocoa. HTML). К сожалению, я продолжаю бить дорожных блоков! Не может подкласс Array, поскольку он является структурой, создавая мою собственную структуру, вызывает проблемы взаимодействия ObjC (это автоматически, t автоматически), следовательно это опция № 3! Вариант №4: напишите этот код в ObjC ;-) – ColinE

ответ

0

Проблема здесь не массив литералов, также первая инициализация не работает нормально, вы можете получить «тот же» сбой, если вы делаете что:

let arrayInstance: MyArray = MyArray() 
arrayInstance.count 

//OR 
let secondArrayInstance: MyArray = MyArray(objects: ["one"], count: 1) // method used by literals syntax 

Проблема подклассов NSMutableArray, потому что это кластер классов. По словам Apple, нет никаких оснований, чтобы сделать это: определение

There is typically little reason to subclass NSArray. The class does well what it is designed to do—maintain an ordered collection of objects. But there are situations where a custom NSArray object might come in handy. Here are a few possibilities:

Changing how NSArray stores the elements of its collection. You might do this for performance reasons or for better compatibility with legacy code.

Acquiring more information about what is happening to the collection (for example, statistics gathering).

Класс Кластеры

Class clusters are a design pattern that the Foundation framework makes extensive use of. Class clusters group a number of private concrete subclasses under a public abstract superclass. The grouping of classes in this way simplifies the publicly visible architecture of an object-oriented framework without reducing its functional richness. Class clusters are based on the Abstract Factory design pattern.

Альтернативы подклассов NSArray

Before making a custom class of NSArray, investigate NSPointerArray and the corresponding Core Foundation type, CFArray Reference. Because NSArray and CFArray are “toll-free bridged,” you can substitute a CFArray object for a NSArray object in your code (with appropriate casting). Although they are corresponding types, CFArray and NSArray do not have identical interfaces or implementations, and you can sometimes do things with CFArray that you cannot easily do with NSArray. For example, CFArray provides a set of callbacks, some of which are for implementing custom retain-release behavior. If you specify NULL implementations for these callbacks, you can easily get a non-retaining array.

If the behavior you want to add supplements that of the existing class, you could write a category on NSArray. Keep in mind, however, that this category will be in effect for all instances of NSArray that you use, and this might have unintended consequences. Alternatively, you could use composition to achieve the desired behavior.

подклассов NSArray

К подклассу NSArray мы должны переопределить количество и objectAtIndex: методы

Any subclass of NSArray must override the primitive instance methods count and objectAtIndex:. These methods must operate on the backing store that you provide for the elements of the collection.


In concept, an array stores a number of data items, each of which is accessible by index. NSArray expresses this abstract notion through its two primitive methods, count and objectAtIndex:. With these methods as a base, other methods—derived methods—can be implemented;

Статический пример Массив

class Months: NSArray { 

    let months = [ "January", "February", "March", "April", 
        "May", "June", "July", "August", "September", 
        "October", "November", "December" ] 

    override var count: Int { 
     get { 
      return months.count 
     } 
    } 

    override func objectAtIndex(index: Int) -> AnyObject { 
     assert(index < count, "The index is out of bounds") 
     return months[index] 
    } 
} 

Initialization

let months = Months() 

println("My birthday month : \(months.objectAtIndex(6))") 
println("The last month of the year : \(months.lastObject)") 

Массив объектов

class MyArray: NSArray { 

    var array: [AnyObject] = [] 

    func populateWith(#objects: [AnyObject]) { 
     self.array = objects 
    } 

    override var count: Int { 
     get { 
      return array.count 
     } 
    } 

    override func objectAtIndex(index: Int) -> AnyObject { 

     assert(index < count, "The index is out of bounds") 
     return array[index] 
    } 
} 

инициализации

let fruits = MyArray() 
fruits.populateWith(objects: ["Apple", "Banana", "Orange", "Pear", "Cherry"]) 

println("Fruits count : \(fruits.count)") 

подклассов NSMutableArray

Это та же вещь NSArray, но мы должны переопределить эти методы:

  • Количество
  • objectAtIndex:
  • insertObject: atIndex:
  • removeObjectAtIndex:
  • AddObject:
  • removeLastObject
  • replaceObjectAtIndex: withObject:

Я могу добавить пример, если это необходимо

Заключения

Мы можем подклассы NSArray в стриж (только при использовании по умолчанию Initializer Init()), но мы не можем (пока) использовать другие инициализатор (как initWithObjects: кол :).

Итак, я согласен с вами, потому что теперь, самым лучшим решением подклассов класса Кластеров в Objective-C

Class Clusters documentation

NSArray documentation

Надежда, что помогает