Создавая и Используя древовидные структуры

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

Эта задача обсуждает, как создать объекты CFTree, вместить их в структуру деревьев, и затем позже найти, получает и изменяет их. Первый параметр большинства функций CFTree является ссылкой на родительский объект CFTree; сама работа обычно вовлекает один или несколько дочерних элементов того родителя. Другими словами, большинство подпрограмм CFTree работает «вниз» иерархия от данного родителя, но влияния только дочерние элементы того родителя.

Один важный факт для запоминания с работой с объектами CFTree - то, который функционирует, которые воздействуют на дочерние элементы, не являются рекурсивными. Они влияют только на непосредственные дочерние деревья. Если Вы хотите пересечь все поддеревья от какого-либо данного родительского узла, Ваш код должен предоставить пересекающуюся логику.

Создание объекта CFTree

Прежде чем можно будет создать объект CFTree, необходимо определить его контекст. Это означает, что необходимо объявить и инициализировать структуру CFTreeContext. Эта структура имеет следующее определение:

typedef struct {
    CFIndex version;
    void *info;
    const void *(*retain)(const void *info);
    void (*release)(const void *info);
    CFStringRef (*copyDescription)(const void *info);
} CFTreeContext;

info элемент этой структуры указывает на данные, что Вы определяете (и выделите, если необходимый). Другие элементы структуры контекста (за исключением элемента версии) указывают на функции, берущие info указатель как параметр и выполняет определенные операции, связанные с указанным данные, такие как сохранение его, выпуск его и описание его.

Когда Вы должным образом инициализировали a CFTreeContext структура, вызовите CFTreeCreate функция, передающая в указателе на структуру. Перечисление 1 дает пример этого метода.

Перечисление 1  , Создающее объект CFTree

static CFTreeRef CreateMyTree(CFAllocatorRef allocator) {
    MyTreeInfo *info;
    CFTreeContext ctx;
    info = CFAllocatorAllocate(allocator, sizeof(MyTreeInfo), 0);
    info->address = 0;
    info->symbol = NULL;
    info->countCurrent = 0;
    info->countTotal = 0;
    ctx.version = 0;
    ctx.info = info;
    ctx.retain = AllocTreeInfo;
    ctx.release = FreeTreeInfo;
    ctx.copyDescription = NULL;
    return CFTreeCreate(allocator, &ctx);
}

Поскольку этот пример показывает, можно инициализировать элементы указателя функции CFTreeContext структура к NULL если Вы не хотите определять функции обратного вызова для контекста объекта CFTree.

Добавление Дерева к его Родителю

Чтобы иметь любое применение, объект CFTree должен быть вставлен в древовидную структуру; это должно быть помещено в иерархическое отношение к другим объектам CFTree. Чтобы сделать это, необходимо использовать одну из следующих функций CFTree для создания объекта дочерним элементом или одноуровневым деревом в связи с некоторым другим деревом:

Перечисление 2 показывает дочернее дерево, добавляемое списку его родителя дочерних элементов.

Перечисление 2  , Добавляющее ребенка Кфтри к его родителю

/* assume anAddress and curTree already exist */
CFTreeRef child = FindTreeChildWithAddress(curTree, anAddress);if (NULL == child) {
    CFTreeContext ctx;
    child = CreateMyTree(CFGetAllocator(curTree));
    CFTreeGetContext(child, &ctx);
    ((MyTreeInfo *)ctx.info)->address = anAddress;
    CFTreeAppendChild(curTree, child);
    CFRelease(child);
}

Пример кода также иллюстрирует другой аспект интерфейса программирования CFTree. Иногда Вы, возможно, должны изменить определенные с помощью программы данные, связанные с уже создающимся объектом CFTree. Чтобы сделать это, вызовите CFTreeGetContext функция на том объекте получить контекст дерева. Как только у Вас есть эта структура, можно получить доступ к определенным с помощью программы данным через info указатель.

Получение дочерних деревьев

Тип CFTree имеет несколько функций, получающих дочерние деревья. Поскольку одноуровневые деревья находятся в последовательном порядке, Вы обычно используете только два из этих методов для пересечения дочерних деревьев одного родителя, CFTreeGetFirstChild и CFTreeGetNextSibling. Перечисление 3 показывает, как Вы делаете это.

Перечисление 3  , Пересекающее дочерние деревья семенного дерева

static CFTreeRef FindTreeChildWithAddress(CFTreeRef tree, UInt32 addr) {
    CFTreeRef curChild = CFTreeGetFirstChild(tree);
    for (; curChild; curChild = CFTreeGetNextSibling(curChild)) {
        CFTreeContext ctx;
        CFTreeGetContext(tree, &ctx);
        if (((MyTreeInfo *)ctx.info)->address == addr) {
            return curChild;
        }
    }
    return NULL;
}

Не весь CFTree функционирует действие на или дочерние деревья возврата. CFTreeGetParent функция, например, получает семенное дерево данного дерева. CFTreeFindRoot функция получает корневой объект CFTree текущей древовидной структуры — т.е. дерево структуры, не имеющей никакого семенного дерева.

Другие операции со структурами CFTree

Тип CFTree включает две функции, которые очень подобны другим функциям набора. CFTreeApplyFunctionToChildren функция применяет определенную с помощью программы функцию applier к дочерним элементам родительского объекта CFTree. CFTreeSortChildren функциональные виды дочерние элементы родительского объекта CFTree использование функции компаратора, которую можно определить (или использовать, пока оно соответствует CFComparatorFunction введите).