本文整理一些Objective-C中常用的数据结构,特别是一些特殊用法的注意点,如自定义类型作为NSMutableDictionary的key;默认情况下容器都是持有容器元素的引用计数的,后面也会介绍NSMapTable如何支持弱引用。
NSString
初始化
NSString * str = @"hello";
NSString * str2 = str;
与C++的std::string相互转换
NSString * str = @"中国";
// NSString转为utf-8
std::string cstr = [str UTF8String];
// utf-8转为NSString
NSString * str2 = [NSString stringWithUTF8String:cstr.c_str()];
格式化
格式化串,支持类似printf的控制符,以及%@
来支持Objective-C的对象类型
NSString *string1 = [NSString stringWithFormat:@"A string: %@, a float: %1.2f",
@"string", 31415.9265];
- 关于
%@
- 如果对象实现了descriptionWithLocale,则会发该消息;否则,返回description对应的值
- 关于
%s
- 格式化c字符串,由于格式化时会使用系统默认编码格式,结果不可控,尽量不要使用,用
%@
和NSString来代替
其他常用方法
@property (readonly) NSUInteger length;
- (unichar)characterAtIndex:(NSUInteger)index;
- (NSString *)substringFromIndex:(NSUInteger)from;
- (NSString *)substringToIndex:(NSUInteger)to;
- (NSString *)substringWithRange:(NSRange)range;
- (NSComparisonResult)compare:(NSString *)string;
- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask;
- (BOOL)isEqualToString:(NSString *)aString;
- (BOOL)hasPrefix:(NSString *)aString;
- (BOOL)hasSuffix:(NSString *)aString;
- (BOOL)containsString:(NSString *)aString;
- (NSString *)stringByAppendingString:(NSString *)aString;
数组 NSArray & NSMutableArray
NSArray
NSArray是不可变数组类型,对数组的变更方法操作都会返回新的数组
// count属性
@property (readonly) NSUInteger count;
// 实例方法
- (id)objectAtIndex:(NSUInteger)index;
- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithObjects:(const id [])objects count:(NSUInteger)cnt
- (NSArray *)arrayByAddingObject:(id)anObject;
- (NSArray *)arrayByAddingObjectsFromArray:(NSArray *)otherArray;
- (BOOL)containsObject:(id)anObject;
- (NSUInteger)indexOfObject:(id)anObject;
- (NSUInteger)indexOfObject:(id)anObject inRange:(NSRange)range;
- (NSUInteger)indexOfObjectIdenticalTo:(id)anObject;
- (NSUInteger)indexOfObjectIdenticalTo:(id)anObject inRange:(NSRange)range;
- (instancetype)initWithObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION;
- (instancetype)initWithArray:(NSArray *)array;
- (instancetype)initWithArray:(NSArray *)array copyItems:(BOOL)flag;
// 类方法
+ (instancetype)array;
+ (instancetype)arrayWithObject:(id)anObject;
+ (instancetype)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
+ (instancetype)arrayWithObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION;
+ (instancetype)arrayWithArray:(NSArray *)array;
NSMutableArray
NSMutableArray继承自NSArray,因此接受NSArray作为参数的方法,都可以使用NSMutableArray
常用的方法:
@interface NSMutableArray : NSArray
- (void)addObject:(id)anObject;
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;
- (void)removeLastObject;
- (void)removeObjectAtIndex:(NSUInteger)index;
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithCapacity:(NSUInteger)numItems NS_DESIGNATED_INITIALIZER;
@end
@interface NSMutableArray (NSExtendedMutableArray)
- (void)addObjectsFromArray:(NSArray *)otherArray;
- (void)removeAllObjects;
- (void)removeObject:(id)anObject inRange:(NSRange)range;
- (void)removeObject:(id)anObject;
- (void)removeObjectIdenticalTo:(id)anObject inRange:(NSRange)range;
- (void)removeObjectIdenticalTo:(id)anObject;
- (void)removeObjectsInArray:(NSArray *)otherArray;
- (void)removeObjectsInRange:(NSRange)range;
- (void)replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray *)otherArray;
- (void)setArray:(NSArray *)otherArray;
- (void)sortUsingFunction:(NSInteger (*)(id, id, void *))compare context:(void *)context;
- (void)sortUsingSelector:(SEL)comparator;
- (void)insertObjects:(NSArray *)objects atIndexes:(NSIndexSet *)indexes;
- (void)removeObjectsAtIndexes:(NSIndexSet *)indexes;
- (void)replaceObjectsAtIndexes:(NSIndexSet *)indexes withObjects:(NSArray *)objects;
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx NS_AVAILABLE(10_8, 6_0);
- (void)sortUsingComparator:(NSComparator)cmptr NS_AVAILABLE(10_6, 4_0);
@end
集合 NSSet & NSMutableSet
- NSSet: 它是一组单值对象的集合,且NSSet实例中元素是无序的,同一个对象只能保存一个;
- NSMutableSet: 继承自NSSet,是可变集合,支持一些交、并集操作等。
字典 NSDictionary & NSMutableDictionary & NSMapTable
字典是常用的支持键值对查询的容器。
自定义结构如何支持NSMutableDictionary作为key类型
NSMutableDictionary一般使用NSString作为key,但是如果需要支持自定义的类型作为key,需要实现几个方法:
copyWithZone
:NSDictionary的key使用的是copy方法,所以自定义的类必须要实现copyWithZone才可以;hash
和isEqual
:用于判断key是否相同需要用,这也看出NSMutableDictionary的内部实现应该是哈希表;而C++中的map是红黑树实现的。
例子:
// interface
@interface PluginInstance : NSObject <NSCopying>
@property (retain) NSString * pluginId;
@property (retain) NSString * instanceId;
- (id)initWithPluginId:(NSString*)pluginId
instanceId:(NSString*)instanceId;
@end
// implementation
@implementation PluginInstance
- (id)initWithPluginId:(NSString*)pluginId
instanceId:(NSString*)instanceId
{
self = [super init];
if (self) {
self.pluginId = pluginId;
self.instanceId = instanceId;
}
return self;
}
// hash
- (NSUInteger)hash
{
return [self.pluginId hash] + 7 * [self.instanceId hash];
}
- (BOOL)isEqual:(id)object
{
if (![object isKindOfClass:[self class]])
return NO;
PluginInstance * other = (PluginInstance *)object;
return [self.pluginId isEqualToString:other.pluginId] && [self.instanceId isEqualToString:other.instanceId];
}
- (id)copyWithZone:(NSZone *)zone
{
PluginInstance *objectCopy = [[PluginInstance allocWithZone:zone] init];
objectCopy.pluginId = [NSString stringWithString:self.pluginId];
objectCopy.instanceId = [NSString stringWithString:self.instanceId];
return objectCopy;
}
@end
// test
PluginInstance * pluginInstance = [[PluginInstance alloc] initWithPluginId:@"bench" instanceId:@"1234"];
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
dict[pluginInstance] = @"hello world";
NSMapTable支持自定义引用计数的Map
NSMapTable是对NSMutableDictionary的补充,因为NSMutableDictionary对于key和value都是持有引用计数的,而NSMapTable可以指定key或者value是strong强引用计数还是weak弱引用计数。
例如:
// value是弱引用计数的Map
NSMapTable * weakWebviews = [NSMapTable strongToWeakObjectsMapTable];