Вставить объект в конец массива, используя новый литеральный синтаксис
PHP имеет:
arr[] = 'Push this onto my array';
Где строка будет добавлена в конец массива.
Есть ли эквивалент этого в новом буквальном синтаксисе Objective-C? Самый краткий способ, которым я могу думать, делает это:
arr[arr.count] = @"Add me";
но может там что-то получше?
2 ответа
Посмотрите документацию по новому буквальному синтаксису. Когда вы присваиваете массиву с использованием нижнего индекса, вызов переводится в setObject:atIndexedSubscript:
вызов метода:
NSMutableArray *foo = …;
foo[0] = @"bar"; // => [foo setObject:@"bar" atIndexedSubscript:0];
Если бы у вас была собственная реализация изменяемого массива, вы могли бы добавить специальный случай к setObject:atIndexedSubscript:
метод для увеличения массива при назначении за размер массива. Я очень сомневаюсь в дефолте NSMutableArray
Реализация делает что-то подобное, скорее всего, вы просто получите исключение из-за отсутствия индекса. И это действительно то, что NSMutableArray
см. справочную документацию:
Если индекс равен count, элемент добавляется в конец массива, увеличивая массив.
Спасибо Мартин за хедз-ап!
На самом деле я не рекомендую делать это, но Objective-C позволяет расширить setObject:atIndexedSubscript:
метод с вашим собственным кодом. Этот процесс называется "метод Swizzling", и это объясняется здесь: http://darkdust.net/writings/objective-c/method-swizzling
Вот некоторый фактический рабочий код, который демонстрирует процесс. Крутой бит в main()
где я могу использовать fib[-1] = ...
вместо fib[fib.count] = ...
, Конечно, здесь нет огромного преимущества; код не более эффективен и, конечно, труднее для чтения. Но я спасаю от необходимости выписывать fib
" дважды.
Основным недостатком этого подхода является то, что Objective-C на самом деле не имеет каких-либо правил о порядке загрузки категорий, поэтому, если кто-то предоставит категорию с аналогичной функциональностью, это будет проверка, какая из них была загружена последней., (И если бы они случайно выбрали одно и то же имя для своей категории, я думаю, это был бы список, который вообще был загружен).
Итак, суть, не делайте этого, но это возможно.
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface NSMutableArray (NegativeOne)
+(void)load;
-(void)swizzled_setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;
@end
@implementation NSMutableArray (NegativeOne)
+(void)load
{
Method original = class_getInstanceMethod(self, @selector(setObject:atIndexedSubscript:));
Method swizzled = class_getInstanceMethod(self, @selector(swizzled_setObject:atIndexedSubscript:));
method_exchangeImplementations(original, swizzled);
}
-(void)swizzled_setObject:(id)obj atIndexedSubscript:(NSUInteger)idx
{
if (idx == -1) idx = [self count];
[self swizzled_setObject:obj atIndexedSubscript:idx]; // go use the old method: not a typo!
}
@end
int main()
{
int x = 0, y = 1;
NSMutableArray *fib = [NSMutableArray new];
for (int i=0; i < 10; ++i) {
fib[-1] = @(x); // wowie zowie!
int temp = x+y; x = y; y = temp;
}
NSLog(@"%@", fib);
return 0;
}