我正在创建第三方库,我需要找到一种以幂等方式创建唯一标识符的方法。我试着解释一下。
假设您UIViewController
喜欢MyViewController
。该库公开了两个不同的API来注册/注销组件。
当我执行视图控制器的register
时,我需要为控制器创建一个唯一的标识符,该标识符应该有效,直到它将被解除分配。如果我创建此控制器的另一个实例,则标识符应该不同。
换句话说,假设我有
MyViewController* a = // alloc-init
现在在a
范围内,我自己注册
// I'm within viewDidLoad for example
[[LibraryManager sharedManager] registerEntry:self];
此时,我的需求如下:根据我传入的实例创建一个唯一的标识符(在我的库中)。
如果a
想取消注册,则可以简单地执行
// I'm within dealloc for example
[[LibraryManager sharedManager] deregisterEntry:self];
基于传入的实例(self
),我需要检索(以某种方式)先前创建的标识符,以便清除使用register
方法创建的内容。
如果我创建另一个控制器,比如b
,则标识符应与使用a
创建的标识符不同。
我不会依赖委托模式来要求控制器(在这种情况下)通过[[NSUUID UUID] UUIDString];
或类似方式提供唯一标识符。
有没有办法根据传入的实例创建唯一标识符?我正在考虑存储内存地址或类似内容的字符串表示,但它是一种黑客攻击,恕我直言。
答案 0 :(得分:1)
您不清楚自己想做什么,但也可以使用相关参考资料。例如,当您需要对象的唯一标识符时,您将尝试使用以下命令获取它:
NSUUID* uuid = objc_getAssociatedObject(theObject, myKey);
如果对象没有分配唯一ID,那么它将返回nil
。在这种情况下,您可以生成唯一ID并为对象设置它:
if (!uuid)
{
uuid = [NSUUID UUID];
objc_setAssociatedObject(theObject, myKey, uuid, OBJC_ASSOCIATION_RETAIN);
}
键myKey
只是您图书馆的独特之处。一个常见的策略(例如,用于KVO的上下文)是创建一个静态变量并使用其地址:
static const int foo;
static const void* const myKey = &foo;
您可以将这些组合起来,使密钥保持自己的地址:
static void* const myKey = (void*)&myKey;
无论如何,关联的对象将在与其关联的对象被释放时释放(或者如果在其上设置了不同的关联对象,尽管在您的情况下不会完成)。
不幸的是,这种方法不是线程安全的,因为两个线程都可以尝试查找唯一ID,发现尚未分配任何ID,生成新线程并分配它。最后一个任务将获胜,但与此同时,另一个可能会返回一个最终被替换的ID。实际上,该对象将具有两个不同的ID。
因此,如果两个线程有可能同时尝试查询ID,则需要在方法中提供同步。例如,创建一个串行GCD队列,并dispatch_sync()
一个包含上述代码的块到该队列。