Return 幂等方式的唯一标识符
Return an unique identifier in a idempotent way
我正在创建第三方库,我需要找到一种以幂等方式创建唯一标识符的方法。我会尽力解释。
假设你 UIViewController
喜欢 MyViewController
。该库向 register/deregister 一个组件公开了两个不同的 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];
或类似方式提供唯一标识符。
有没有办法根据传入的实例创建唯一标识符?我正在考虑存储内存地址或类似的字符串表示形式,但恕我直言,这是一种技巧。
还不完全清楚您想做什么,但您可以使用关联的参考资料。例如,当你想要一个对象的唯一标识符时,你会尝试使用:
NSUUID* uuid = objc_getAssociatedObject(theObject, myKey);
如果对象尚未分配唯一 ID,则将 return 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,发现 none 已经分配,生成一个新的 ID,然后分配它。最后一个分配将获胜,但与此同时,另一个可能 returned 了一个最终被替换的 ID。实际上,对象会有两个不同的 ID。
因此,如果两个线程有可能同时尝试查询 ID,您需要在您的方法中提供同步。例如,创建一个串行 GCD 队列和 dispatch_sync()
一个包含上述代码的块到该队列。
我正在创建第三方库,我需要找到一种以幂等方式创建唯一标识符的方法。我会尽力解释。
假设你 UIViewController
喜欢 MyViewController
。该库向 register/deregister 一个组件公开了两个不同的 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];
或类似方式提供唯一标识符。
有没有办法根据传入的实例创建唯一标识符?我正在考虑存储内存地址或类似的字符串表示形式,但恕我直言,这是一种技巧。
还不完全清楚您想做什么,但您可以使用关联的参考资料。例如,当你想要一个对象的唯一标识符时,你会尝试使用:
NSUUID* uuid = objc_getAssociatedObject(theObject, myKey);
如果对象尚未分配唯一 ID,则将 return 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,发现 none 已经分配,生成一个新的 ID,然后分配它。最后一个分配将获胜,但与此同时,另一个可能 returned 了一个最终被替换的 ID。实际上,对象会有两个不同的 ID。
因此,如果两个线程有可能同时尝试查询 ID,您需要在您的方法中提供同步。例如,创建一个串行 GCD 队列和 dispatch_sync()
一个包含上述代码的块到该队列。