Когда вызывается метод IEnumerator.Reset ()?

Я потратил много времени, пытаясь вычислить в реальном времени количество строк для входного TextView (скажем, в окне ввода текста чата), и единственное решение, которое работает в таком случае, это Люк Чейз (по какой-то причине кадр) Подход .height, по-видимому, обновляет только 3-ю или 4-ю букву, введенную в textView, и поэтому не является точной).

Однако, как упомянул комментатор, существует небольшая ошибка, из-за которой сгенерированные пользователем разрывы строк ("\ n" или нажатие клавиши на клавиатуре) не учитываются должным образом. Даже более странно, он только «пропускает» первый такой разрыв строки, все последующие правильно перехвачены (скажем, если вы перейдете на строку 4 раза, она вернет только 3 строки, явно пропустившие первый разрыв строки).

Итак, чтобы обойти эту ошибку, я просто смотрю запись первого такого переноса строки (символ «\ n») и вручную добавляю строку к числу строк, которое возвращает метод gliph.

В коде, который дает:

    func offSetTableViewIfNeeded() {
    let numberOfGlyphs = textView.layoutManager.numberOfGlyphs
    var index : Int = 0
    var lineRange = NSRange(location: NSNotFound, length: 0)
    var currentNumOfLines : Int = 0
    var numberOfParagraphJump : Int = 0

    while index < numberOfGlyphs {
        textView.layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
        index = NSMaxRange(lineRange)
        currentNumOfLines += 1

        // Observing whether user went to line and if it's the first such line break, accounting for it.
        if textView.text.last == "\n", numberOfParagraphJump == 0 {
            numberOfParagraphJump = 1
        }
    }

    currentNumOfLines += numberOfParagraphJump

    print("Number of lines is:", currentNumOfLines)

Надеюсь, что это поможет другим, кто боролся со сверхъестественным поведением ввода textView (не может понять, почему Apple не предоставляет метод # line out из коробки!).

9
задан Farah_online 16 October 2010 в 05:33
поделиться

1 ответ

В то время как я соглашаюсь с комментариями относительно остаточных частей и что Reset() не используется кодом платформы, и блоки генератора действительно выдают исключения, я не соглашаюсь, что это абсолютно бесполезно. Мое понимание относительно того, почему блоки генератора выдают исключения на сбросе, из-за опасений по поводу любого созданного работоспособного состояния. Самая природа блоков генератора делает их особенно il-suited для восстановленных операций, но это не означает, что восстановленный перечислитель плохо или плохо разработан.

Рассматривают сложное перечисление, созданное путем создания сотен различных перечислителей 'декоратора'. Стоимость построения такого графа объектов ненезначительна. Теперь также полагайте, что источник этого сложного перечисления является динамичным, но для обработки причин, требуется семантика снимка. В таком сценарии мы можем создать эту 'стопку перечислителя' и на первое MoveNext() вызов, снимок источника взят. Сложное перечисление/проекция/и т.д. выполняется, и результаты получены. Теперь мы хотим выполнить эту операцию снова, начиная вначале. Reset() обеспечивает механизм для этой всей стопки перечислителя, чтобы повторно инициализировать к, он - начальное состояние, не имея необходимость восстанавливать весь граф объектов. Далее, это разрешает нам сохранять конструкцию графа объектов разделенной от потребителя, который должен выполнить это сложное перечисление многократно.

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

Ниже пример исходного перечислителя, который загружает документ список и затем перечисляет по тому списку. Сброс перечислителя заставляет список быть повторно загруженным. Далее, перечислитель декоратора определяется, который мог использоваться для обертывания перечислителя списка (или любого перечислителя) для проектирования объектов перечислителя. Я назвал его SelectEnumerator, так как это выполняет ту же роль Enumerable.Select

// excuse the poorly named types
public class ListDownloaderEnumerator<T> : IEnumerator<T>
{
    private int index = -1;
    private readonly string url;
    private IReadOnlyList<T> items;
    public ListDownloaderEnumerator(string url)
    {
        this.url = url;
    }
    public bool MoveNext()
    {
        // downloading logic removed for brevity
        if (items == null) download(url);
        index = index + 1;
        return index < items.Count;
    }
    public void Reset()
    {
        index = -1;
        items = null;
    }
    // other parts of IEnumerator<T>, such as Current
}

public class SelectEnumerator<T, TResult> : IEnumerator<T>
{
    private readonly IEnumerator<T> enumerator;
    private readonly Func<T, TResult> projection;
    public SelectEnumerator(IEnumerator<T> enumerator, Func<T, TResult> projection)
    {
        this.enumerator = enumerator;
        this.projection = projection;
    }
    public bool MoveNext()
    {
        return enumerator.MoveNext();
    }
    public void Reset()
    {
        enumerator.Reset();
    }
    // other parts of IEnumerator<T>, such as Current
}

// somewhere else in the application
// we can now write processing code without concern for sourcing
// and perhaps projecting the data. this example is very simple,
// but using decorator enumerator you can accomplish very complex
// processing of sequences while maintaining small, testable, and
// composable classes. it also allows for highly configurable
// processing, since the decorators become building blocks.
public class DownloadedDataProcessor
{
    private readonly IEnumerator<MyProjectedListItem> enumerator;
    public DownloadedDataProcessor(IEnumerator<MyProjectedListItem> enumerator)
    {
        this.enumerator = enumerator;
    }
    public void ProcessForever()
    {
        while (true)
        {
            while (enumerator.MoveNext())
            {
                Process(enumerator.Current);
            }

            enumerator.Reset();
        }
    }
    private void Process(MyProjectedListItem item)
    {
        // top secret processing
    }
}

0
ответ дан 4 December 2019 в 09:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: