Я изменил установщики по умолчанию для класса Objective-C, чтобы разрешить какой-то KVO без фактического добавления наблюдателя к свойству. Это прекрасно работает. Но в некоторых случаях мне нужно присвоить этой системе сотни тысяч свойств.
Таким образом, по соображениям производительности у меня есть собственный дескриптор свойства, который позволяет напрямую устанавливать ivar. Пытаясь настроить производительность, я сохраняю некоторую информацию о свойстве.
Еще одно место, которое я очень осторожно изменю, — это использование object_setIvar(), на которое приходится 60% процессорного времени при назначении в соответствии с инструментами. Причина в том, что object_setIvar вызывает _class_getVariable, что занимает в 3 раза больше времени, чем фактическое назначение (objc_storeStrong()).
Короче говоря: поскольку я могу заранее кэшировать всю информацию в свойстве класса как часть моего дескриптора свойства, как я могу быстрее установить ivar (избегая object_setIvar())?
Вот фактическая функция установки объекта моего класса дескриптора свойства (есть также эквивалент для установки числовых значений):
- (id)setObjectValueNoKVOForOwner:(id)instance newObject:(id)newObject
{
Class cls = object_getClass(instance);
BOOL retainNewValue, copyNewValue, releaseOldValue;
switch (self.setterSemantics)
{
case MemberDescriptionSetterSemanticsAssign:
retainNewValue = NO;
copyNewValue = NO;
releaseOldValue = NO;
break;
case MemberDescriptionSetterSemanticsRetain:
retainNewValue = YES;
copyNewValue = NO;
releaseOldValue = YES;
break;
case MemberDescriptionSetterSemanticsCopy:
retainNewValue = NO;
copyNewValue = YES;
releaseOldValue = YES;
break;
}
if (!_ivar)
{
_ivar = class_getInstanceVariable(cls, self.attributes.ivarName);
}
if (_ivar)
{
id oldObject = object_getIvar(instance, _ivar);
if (newObject != oldObject)
{
if (retainNewValue)
{
newObject = [newObject retain];
}
else if (copyNewValue)
{
newObject = [newObject copy];
}
object_setIvar(instance, _ivar, newObject); // Improve this: avoid _class_getVariable
if (releaseOldValue)
{
[oldObject release];
}
}
}
return [newObject autorelease];
}
Обновление:
Я нашел источники, связанные с object_setIvar(): https://github.com/opensource-apple/objc4/blob/master/runtime/objc-class.mm http://www.opensource.apple.com/source/objc4/objc4-532.2/runtime/objc-private.h http://www.opensource.apple.com/source/objc4/objc4-532.2/runtime/objc-runtime-new.mm
Не кажется "этим" злом реализовать собственную версию object_setIvar(), просто добавив к ней известный класс в качестве аргумента. К сожалению, для этого требуется частный заголовочный файл. Поскольку я ориентируюсь на iOS, кажется, на данный момент я должен отказаться от надежд.
Обновление 2:
Я нашел этот комментарий в том месте, где он тратит время в источниках Apple:
"// FIXME: это можно оптимизировать."
Так что я, вероятно, должен сдаться на этом этапе и надеяться, что это будет улучшено в будущем. На самом деле я действительно не понимаю, что есть такое узкое место в чем-то таком простом, как установка значения для свойства. С другой стороны, приятно видеть, что программисты в Apple тоже люди :).