Как указано в этот ответ строковые литералы являются неизменяемыми строковыми объектами и получают их адрес во время компиляции - поэтому вам не нужно создавать несколько экземпляров одной и той же строки литерала во время выполнения.
NSString *myString = @"Hello";
Итак, мы просто назначаем myString указателю на строковый литерал.
NSString *myString = [NSString stringWithString:@"Hello"];
Вторая строка создает объект с помощью удобного конструктора, но поскольку мы имеем здесь дело с неизменяемыми объектами, это приводит к тому же значению указателя на строковый литерал - так вы получите тот же результат, что и в первом варианте (хотя, возможно, выполняет некоторые дополнительные вызовы методов).
Так что, кажется, что упомянутые вами варианты делают то же самое, но 2-й также может выполнять некоторые дополнительные вызовы.
Небольшой пример, иллюстрирующий, что происходит:
NSString* tString = @"lala";
NSString* tString2 = @"lala";
NSString* tString3 = [NSString stringWithString:@"lala"];
NSString* tString4 = [NSString stringWithFormat:@"%@", @"lala"];
NSLog(@"%p %d", tString, [tString retainCount]);
NSLog(@"%p %d", tString2, [tString2 retainCount]);
NSLog(@"%p %d", tString3, [tString3 retainCount]);
NSLog(@"%p %d", tString4, [tString4 retainCount]);
Вывод:
0xd0418 2147483647
0xd0418 2147483647
0xd0418 2147483647
0x50280e0 1