Здесь много хороших ответов, но я хотел бы отметить, что их можно очень просто расширить, чтобы добиться более сложной сортировки. Единственное, что вам нужно сделать, это использовать оператор OR для цепочки сравнения, например:
objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )
Где fn1
, fn2
, ... являются функциями сортировки, которые возвращают [- 1,0,1]. Это приводит к «сортировке по fn1», «сортировке по fn2», которая в значительной степени равна ORDER BY в SQL.
Это решение основано на поведении оператора ||
, который оценивает значение первое оцениваемое выражение, которое может быть преобразовано в true .
Простейшая форма имеет только одну встроенную функцию:
// ORDER BY last_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) )
Имея два шага с last_nom
, порядок сортировки first_nom
будет выглядеть так:
// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) ||
a.first_nom.localeCompare(b.first_nom) )
Общая функция сравнения может быть примерно такой:
// ORDER BY
let cmp = (a,b,n)=>a[n].localeCompare(b[n])
Эта функция может быть расширена для поддержки числовых полей , чувствительность к регистру, произвольные типы данных и т. д.
Вы можете использовать его с привязкой к ним по приоритету сортировки:
// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> cmp(a,b, "last_nom") || cmp(a,b, "first_nom") )
// ORDER_BY last_nom, first_nom DESC
objs.sort((a,b)=> cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )
// ORDER_BY last_nom DESC, first_nom DESC
objs.sort((a,b)=> -cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )
. Дело в том, что чистый JavaScript с функциональным подходом может принять вас долгий путь без внешних библиотек или сложного кода. Это также очень эффективно, так как не нужно выполнять синтаксический анализ строк
Будьте проще:
+(instancetype)sharedInstance
{
static dispatch_once_t pred;
static id sharedInstance = nil;
dispatch_once(&pred, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (void)dealloc
{
// implement -dealloc & remove abort() when refactoring for
// non-singleton use.
abort();
}
Вот и все. Переопределение retain
, release
, retainCount
и всего остального просто скрывает ошибки и добавляет кучу ненужного кода. Каждая строка кода - это ошибка, ожидающая своего появления. В действительности, если вы вызываете dealloc
для вашего общего экземпляра, у вас есть очень серьезная ошибка в вашем приложении . Эта ошибка должна быть исправлена, а не скрыта.
Этот подход также поддается рефакторингу для поддержки не-одиночных режимов использования. Практически каждый синглтон, выживший после нескольких выпусков, в конечном итоге будет преобразован в не-синглтонную форму. Некоторые (например, NSFileManager
) продолжают поддерживать одноэлементный режим, а также поддерживают произвольное создание экземпляров.
Обратите внимание, что вышесказанное также «просто работает» в ARC.
Если вы хотите провести модульное тестирование вашего синглтона, вы также должны сделать его так, чтобы вы могли заменить его на имитированный синглтон и / или сбросить его до нормального:
@implementation ArticleManager
static ArticleManager *_sharedInstance = nil;
static dispatch_once_t once_token = 0;
+(ArticleManager *)sharedInstance {
dispatch_once(&once_token, ^{
if (_sharedInstance == nil) {
_sharedInstance = [[ArticleManager alloc] init];
}
});
return _sharedInstance;
}
+(void)setSharedInstance:(ArticleManager *)instance {
once_token = 0; // resets the once_token so dispatch_once will run again
_sharedInstance = instance;
}
@end
// See Mike Ash "Care and Feeding of Singletons"
// See Cocoa Samurai "Singletons: You're doing them wrong"
+(MySingleton *)singleton {
static dispatch_once_t pred;
static MySingleton *shared = nil;
dispatch_once(&pred, ^{
shared = [[MySingleton alloc] init];
shared.someIvar = @"blah";
});
return shared;
}
Имейте в виду, что dispatch_once не является повторно входящим , поэтому вызов себя изнутри блока dispatch_once приведет к блокировке программы.
Не пытайтесь защищаться от самого себя. Если вы не программируете фреймворк, относитесь к своему классу как к нормальному, а затем придерживайтесь единой идиомы выше. Думайте об идиоме синглтона как об удобном методе, а не как об определяющей черте вашего класса. Вы хотите относиться к своему классу как к нормальному классу во время модульного тестирования, поэтому можно оставить доступный конструктор.
Не утруждайте себя использованием allocWithZone:
alloc
. Зоны памяти больше не используются в Objective-C, поэтому allocWithZone:
сохраняется только для совместимости со старым кодом. NSAllocateObject()
и class_createInstance()
. Метод фабрики-одиночки всегда возвращает один из этих трех типов:
id
, чтобы указать, что возвращаемый тип не полностью известен (случай, когда вы строите класс кластер). instancetype
чтобы указать, что возвращаемый тип является экземпляром включающего класса. MySingleton
в примере), чтобы упростить его. Поскольку вы пометили эту iOS, альтернативой одиночному файлу является сохранение ivar делегату приложения, а затем использование вспомогательного макроса, который вы можете переопределить, если передумаете:
#define coreDataManager() \
((AppDelegate*)[[UIApplication sharedApplication] delegate]).coreDataManager