Использование экземпляров NSView в качестве ключей NSDictionary?

Я пытаюсь создать полусложный набор анимаций просмотра (подумайте об анимированной версии формы NSMatrix, где строки скользят по мере добавления или удаления других строк), и для создания анимации я создаю небольшой вспомогательный класс. .

Там я должен отслеживать различные представления, их упорядоченные индексы и некоторые другие значения, связанные с их анимацией.

С этой целью я использую экземпляр NSArray для отслеживания порядка (индексов) представлений, и я хотел бы использовать NSDictionary с представлениями в качестве ключей для отслеживания значений (сами значения находятся в вложенные словари). т.е. Я хотел бы иметь возможность сделать что-то, например (псевдокод):

NSMutableDictionary* viewValuesDict = [NSDictionary dictionary];

// Loop thru an ordered NSArray
for( (NSView*) view in viewsArray ) {
    // Get some values we'll need later
    NSDictionary* associatedValues = [view getSomeValues];

    // ...and put them into viewValuesDict...
    [viewValuesDict setObject:associatedValues forKey:view];

    // and then things break because the NSView 'view'
    // doesn't support copyWithZone.... darn
}

Проблема в том, что я, конечно, не могу использовать экземпляры NSView в качестве ключей словаря, потому что ключи добавляются с помощью copyWithZone, который NSView не реализует.

Итак, как лучше всего получить уникальный ключ для экземпляра NSView? Я мог бы предположительно использовать [obj description], так как адрес памяти, который вы возвращаете, является идеальным UID, но, конечно, система должна работать с любым подклассом NSView, который может возвращать что-то совершенно другое, так что это нехорошо.

Или мне стоит попробовать что-то совсем другое? Может есть альтернатива NSDictionary, где ключи просто не копируются? Потому что в этом случае мне действительно не нужно копировать ключи.


person Flambino    schedule 05.12.2010    source источник


Ответы (4)


Иногда бывают случаи, когда вы хотите использовать представление (будь то NS или UI) в качестве ключа в словаре. Я сталкивался с одной такой ситуацией. Я бы предпочел использовать objc_setAssociatedObject, но для этого требуется Snow Leopard. Упаковка с помощью NSValue будет работать, но если вам нужно выполнять много-много операций поиска с заданным представлением, непрерывная упаковка и распаковка указателей может стать утомительной.

Существует два варианта создания словаря NSView => <object>.

  1. Используйте NSMapTable
  2. Используйте CFMutableDictionaryRef

NSMapTable — это класс, представленный в версии 10.5. это очень похоже на NSMutableDictionary, за исключением того, что у него есть дополнительные возможности, которые позволяют лучше работать со сборкой мусора. В вашем случае вам, вероятно, понадобится таблица карт со «слабыми» ключами и «сильными» значениями, но прочтите документацию, чтобы узнать обо всех забавных деталях.

CFMutableDictionaryRef — эквивалент Core Foundation NSDictionary (они соединены по бесплатному мосту), но у него есть некоторые дополнительные возможности создания. Вы создаете один, используя CFDictionaryCreateMutable(), и ему нужны два параметра struct. Одна представляет собой структуру, которая определяет поведение управления памятью (и другое), как обращаться с ключами словаря, а другая представляет собой struct для определения поведения значений. Вы можете создать CFMutableDictionaryRef с параметрами сохранения ключей (вместо их копирования) и последующего сохранения значений. Как только вы это сделаете, вы можете привести CFMutableDictionaryRef к NSMutableDictionary и использовать его так, как вы ожидаете, только ключи будут сохранены, а не скопированы.

person Dave DeLong    schedule 05.12.2010
comment
Ооочень интересно! Я определенно должен попробовать их. Как я уже сказал в другом комментарии, я нацелился на Snow Leopard, но мне не нужно, чтобы что-то задерживалось очень долго, поэтому objc_setAssociatedObject может быть излишним. Однако NSMapTable и CFMutableDictionaryRef звучат так, как будто они могут идеально соответствовать всем требованиям. Спасибо! - person Flambino; 06.12.2010

Используйте NSMapTable вместо NSDictionary (конечно, вы должны быть уверены, что тщательно управляете временем жизни вашего объекта, если вы не используете сборку мусора). В этой статье содержится хорошее описание того, как ее использовать. .

person Nicholas Riley    schedule 05.12.2010

Как сказал andyvn22, реорганизуйтесь! Но если это нецелесообразно:

  • Если вы ориентируетесь на Snow Leopard и ассоциации, скорее всего, будут сохраняться в течение всего времени существования представлений, используйте objc_setAssociatedObject().
  • В противном случае используйте [NSValue valueWithNonretainedObject:] вместо -description. (Как говорится, он не сохраняет объект, но сохраняет ваш массив.)
person Jens Ayton    schedule 05.12.2010
comment
Реорганизацию можно было бы выполнить, но я надеялся на более короткий путь :-) Я ориентируюсь на Snow Leopard, но мне нужны значения только на очень короткое время, поэтому я думаю, что пропущу objc_setAssociatedObject(). Но valueWithNonretainedObject: может быть выходом. попробую - спасибо! - person Flambino; 06.12.2010

Создавайте свои словари так, чтобы одним из их значений было представление; затем перестройте код так, чтобы вам не нужно было искать словарь на основе представления, а начать либо со словарей, либо с индекса (помещая словари в массив), либо с уникального идентификатора вашего собственного создания (помещая словари в массив). словарь; идентификатор может быть таким же простым, как порядковый номер для каждого нового представления, которое вы начинаете отслеживать). Если вы не делаете что-то очень сложное и динамичное, можно избежать необходимости поиска информации, имеющей только NSView.

person andyvn22    schedule 05.12.2010
comment
Спасибо. Да, я тоже думал об этом. Я просто подумал, что должен быть какой-то способ просто использовать любой старый объект в качестве ключа. Мне кажется (по крайней мере мне), что использование объектов в качестве ключей было бы простым способом подделки нескольких дополнительных свойств объекта (хотелось бы, чтобы категории каким-то образом позволяли вам добавлять ивары... вздох). - person Flambino; 06.12.2010
comment
Неа. Ключи имеют действительно специфические свойства; это то, что делает словари эффективными. Если вы действительно пытаетесь добавить некоторые дополнительные свойства к каждому NSView, почему вы не создаете подклассы? Именно для этого и нужны подклассы! - person andyvn22; 06.12.2010
comment
Потому что код должен работать с любым представлением, которое вы ему предлагаете, а не только с определенными подклассами. И кроме того, речь идет только о хранении нескольких связанных значений в течение очень короткого времени (достаточно долгого, чтобы подготовить результирующий NSViewAnimation, но это все), поэтому, хотя я мог сделать некоторую композицию объектов и обернуть NSViews, это казалось излишним. И вообще, NSMapTable отлично работает :-) - person Flambino; 06.12.2010