Wisdom of the Net
Returning multiple objects from a method
// Return via reference variables
// Violates Apple coding guidelines
@implementation ViaReferenceVars
- (void)userName:(NSString **)userName userID:(NSString **)userID {
// …
*userName = computedUserName;
*userID = computedUserID;
}
- (void)test {
NSString *userName;
NSString *userID;
[self userName:&userName userID:&userID];
display(@”\nReturn via reference variables”);
display(@”ViaReferenceVars - name: ‘%@’, userID: ‘%@’”, userName, userID);
}
@end
// Return via ivar properties
// Pollutes ivar space
@interface ViaIVars ()
@property NSString *userNameProperty;
@property NSString *userIDProperty;
@end
@implementation ViaIVars
- (void)userNameUserID {
// …
self.userNameProperty = computedUserName;
self.userIDProperty = computedUserID;
}
- (void)test {
[self userNameUserID];
display(@”\nReturn via ivar properties”);
display(@”ViaIVars - name: ‘%@’, userID: ‘%@’”, self.userNameProperty, self.userIDProperty);
}
@end
// Return via class
@interface DataModel : NSObject
@property NSString *userName;
@property NSString *userID;
@end
@implementation DataModel
@end
@implementation ViaClass
- (DataModel *)userNameUserID {
// …
DataModel *nameAndID = [DataModel new];
nameAndID.userName = computedUserName;
nameAndID.userID = computedUserID;
return nameAndID;
}
- (void)test {
DataModel *dataModel = [self userNameUserID];
display(@”\nReturn via class”);
display(@”ViaClass - name: ‘%@’, userID: ‘%@’”, dataModel.userName, dataModel.userID);
}
@end
// Return via class factory
@interface DataModel1 : NSObject
@property NSString *userName;
@property NSString *userID;
+ (id)userName:(NSString *)userName userID:(NSString *)userID;
@end
@implementation DataModel1
+ (id)userName:(NSString *)userName userID:(NSString *)userID {
DataModel1 *nameAndID = [DataModel1 new];
nameAndID.userName = userName;
nameAndID.userID = userID;
return nameAndID;
}
@end
@implementation ViaClassFactory
- (DataModel1 *)userNameUserID {
// …
return [DataModel1 userName:computedUserName userID:computedUserID];
}
- (void)test {
DataModel1 *dataModel = [self userNameUserID];
display(@”\nReturn via class factory”);
display(@”ViaClassFactory - name: ‘%@’, userID: ‘%@’”, dataModel.userName, dataModel.userID);
}
@end
// Return via dictionary
// Meets Apple coding guidelines, messy
@implementation ViaDictionary
- (NSDictionary *)userNameUserID {
// …
return [NSDictionary dictionaryWithObjectsAndKeys:computedUserName, @"name", computedUserID, @"id", nil];
}
- (void)test {
NSDictionary *nameAndID = [self userNameUserID];
display(@”\nReturn via dictionary”);
display(@”ViaDictionary - name: ‘%@’, userID: ‘%@’”, [nameAndID objectForKey:@"name"], [nameAndID objectForKey:@"id"]);
}
@end
// Return via dictionary literals
// Meets Apple coding guidelines, neat, concise
@implementation ViaDictionaryLiterals
- (NSDictionary *)userNameUserID {
// …
return @{@”name”:computedUserName, @”id”:computedUserID};
}
- (void)test {
NSDictionary *nameAndID = [self userNameUserID];
display(@”\nReturn via dictionary literals”);
display(@”ViaDictionaryLiterals – name: ‘%@’, userID: ‘%@’”, nameAndID[@"name"], nameAndID[@"id"]);
}
@end
// Return via array (new style)
// Closest to python style
@implementation ViaArrayLiterals
- (NSArray *)userNameUserID {
// …
return @[computedUserName, computedUserID];
}
- (void)test {
NSArray *nameAndID = [self userNameUserID];
display(@”\nReturn via reference variables”);
display(@”ViaArrayLiterals - name: ‘%@’, userID: ‘%@’”, nameAndID[0], nameAndID[1]);
}
@end
Singleton using a block
Kevin Ballard from stackoverflow
Singleton using a block: Kevin Ballard from stackoverflow
+ (id)sharedInstance {
static MyClass sharedInstance;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
sharedInstance = [MyClass alloc];
sharedInstance = [sharedInstance init];
});
return sharedInstance;
}
See the dispatch_once: man pageHeapshot
Use Heapshot to find memory creep, see: bbum blog
Basically there method is to run Instruments allocate tool, take a heapshot, run an intuition of your code and another heapshot repeating 3 or 4 times. This will indicate memory that is allocated and not released during the iterations.
To figure out the results disclose to see the individual allocations.
If you need to see where retains, releases and autoreleases occur for an object use instruments:
Run in instruments, in Allocations set “Record reference counts” on on (you have to stop recording to set the option). Cause the problem code to run, stop recording, search for there ivar of interest, drill down and you will be able to see where all retains, releases and autoreleases occurred.
Display View Hierarchy
- (void)showViewHierarchy:(UIView *)aView level:(int)level
{
for (UIView *subView in aView.subviews) {
NSLog(@”%*sview: %i”, level*4,“”, subView.tag);
if (subView.tag >= 100 && subView.subviews.count) {
[self showViewHierarchy:subView level:level+1];
}
}
}
NSLog Replacement
Probably from BYU CocoaHeads
void Display(NSString *format, …) {
if (format == nil) {
printf(“nil\n”);
return;
}
// Get a reference to the arguments that follow the format parameter
va_list argList;
va_start(argList, format);
// Perform format string argument substitution, reinstate %% escapes, then print
NSString *s = [[NSString alloc] initWithFormat:format arguments:argList];
printf(“%s\n”, [[s stringByReplacingOccurrencesOfString:@"%%" withString:@"%%%%"] UTF8String]);
[s release];
va_end(argList);
}
Q&D AES encryption example
If you are doing encryption and don’t understand IV, CBC, PKCS padding or how to create good keys, please get competent help. It only takes one bug in cryptography to complete destroy the security.
#import <CommonCrypto/CommonCryptor.h>
+ (NSData *)doCipher:(NSData *)dataIn
iv:(NSData *)iv
key:(NSData *)symmetricKey
context:(CCOperation)encryptOrDecrypt
{
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0; // Number of bytes moved to buffer.
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];
ccStatus = CCCrypt( encryptOrDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
symmetricKey.bytes,
kCCKeySizeAES128,
iv.bytes,
dataIn.bytes,
dataIn.length,
dataOut.mutableBytes,
dataOut.length,
&cryptBytes);
if (ccStatus != kCCSuccess) {
NSLog(@”CCCrypt status: %d”, ccStatus);
}
dataOut.length = cryptBytes;
return dataOut;
}
// Also add Security.framework to your project.