Возникло исключение — делегат NSTextView — textViewDidChangeSelection: уведомление

Я создаю свое первое приложение для Mac, текстовый редактор. Он основан на документах, а Document.xib имеет nstextview. Я сделал класс Document делегатом textview. Я реализую метод:

-(void)textViewDidChangeSelection:(NSNotification *)notification
{
NSRange range=self.textView.selectedRange;
NSLog(@" %@ ",[[self.textView textStorage] attributesAtIndex: range.location
                                              effectiveRange: &range]); 

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

*** -[NSConcreteTextStorage attributesAtIndex:effectiveRange:]: Range or index   
out of bounds

Я попытался выполнить отладку с помощью блока @try: @catch:, и кажется, что описанный выше метод всегда выдает это исключение. Если я заменю:

range.location

с участием

(range.location-1)

это исключение выдается только тогда, когда курсор находится в индексе 0.

Кто-нибудь знает, что происходит?


person user2637479    schedule 31.07.2013    source источник
comment
range.location-1 будет недопустимым числом, когда self.textView.selectedRange==0 (нет выбора или он начинается с самого начала.   -  person Vincent Gable    schedule 24.01.2014


Ответы (2)


эффективный диапазон – это не диапазон, используемый методом для определения диапазона сканирования атрибутов. Это диапазон, который будет содержать после возврата диапазон, в котором атрибуты и значения совпадают с атрибутами в индексе attributeAtIndex (т. е. метод присвоит другое значение вашей переменной диапазона).

Если вы хотите ограничить диапазон, используемый методом для поиска атрибутов, выбранным диапазоном, используйте следующий метод с параметром rangeLimit, установленным на выбранный диапазон:

(NSDictionary *)attributesAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange inRange:(NSRange)rangeLimit

-(void)textViewDidChangeSelection:(NSNotification *)notification
{
    NSRange selectedRange=self.textView.selectedRange;
    NSRange effectiveRange;
    if(selectedRange.length > 0) {
        NSLog(@" %@ ",[[self.textView textStorage] attributesAtIndex:selectedRange.location
       longestEffectiveRange:&effectiveRange inRange:selectedRange]); 
    }
}

Похоже, что метод не работает, когда длина selectedRange равна 0. Вот почему selectedRange.length проверяется перед его вызовом.

person Jean-Pierre    schedule 31.07.2013
comment
Спасибо за ваше время. Он снова падает (диапазон или индекс за пределами). Разве не следует инициализировать EffectiveRange? Есть ли что-нибудь, связанное с Interface Builder, что я могу упустить? - person user2637479; 31.07.2013
comment
Что ж, ваше свойство textView должно быть IBOutlet, подключенным к фактическому NSTextView в IB. Вы проверили значения selectedRange, чтобы убедиться, что они имеют смысл (selectedRange.location, selectedRange.length)? EffectiveRange будет инициализирован методом (т. е. & EffectiveRange). - person Jean-Pierre; 31.07.2013
comment
Да, у меня есть NSLog @finally (@try-@catch block), и они в полном порядке. IBOutlet установлен, как и делегат textview. - person user2637479; 31.07.2013
comment
Есть ли шанс, что тот факт, что у меня нет префикса в моем классе Document (Document.m), что-то испортит во время выполнения? - person user2637479; 31.07.2013
comment
Кажется, чтобы обойти это, вы пропустили метод, когда длина selectedRange равна 0 (т.е. нет выбора) (см. мое редактирование выше). Затем вам нужно «еще», чтобы определить, что делать, когда выбора нет. - person Jean-Pierre; 31.07.2013

Это было какое-то время для этой темы, но в любом случае я нашел это, если это будет полезно для кого-то:

Вызов - attributeAtIndex: по-прежнему работает нормально, когда range.length == 0, но не работает, когда местоположение находится в конце строки. Это явно ошибка, потому что диапазон {string_length, 0} ЯВЛЯЕТСЯ ДЕЙСТВИТЕЛЬНЫМ диапазоном.

Чтобы преодолеть это, я использую -typingAttributes:, который дает атрибуты для текущего стиля набора текста.

NSRange currange = [self.textViewEditor selectedRange];
NSLog(@"range %@", NSStringFromRange(currange));
NSDictionary *dict;
if (currange.length==0)
    dict = [self.textViewEditor typingAttributes];
else
    dict = [self.textViewEditor.textStorage attributesAtIndex:currange.location effectiveRange:&range];
person Merlevede    schedule 23.01.2014