blob: d0006cfe313fb834edb5aa2d34c913a99801a0f6 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/mac/objc_release_properties.h"
#include <memory>
#include <objc/runtime.h>
#include "base/logging.h"
#include "base/memory/free_deleter.h"
namespace {
bool IsRetained(objc_property_t property) {
// The format of the string returned by property_getAttributes is documented
// at
// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW6
const char* attribute = property_getAttributes(property);
while (attribute[0]) {
switch (attribute[0]) {
case 'C': // copy
case '&': // retain
return true;
}
do {
attribute++;
} while (attribute[0] && attribute[-1] != ',');
}
return false;
}
id ValueOf(id obj, objc_property_t property) {
std::unique_ptr<char, base::FreeDeleter> ivar_name(
property_copyAttributeValue(property, "V")); // instance variable name
if (!ivar_name)
return nil;
id ivar_value = nil;
Ivar ivar = object_getInstanceVariable(obj, &*ivar_name,
reinterpret_cast<void**>(&ivar_value));
DCHECK(ivar);
return ivar_value;
}
} // namespace
namespace base {
namespace mac {
namespace details {
void ReleaseProperties(id self, Class cls) {
unsigned int property_count;
std::unique_ptr<objc_property_t[], base::FreeDeleter> properties(
class_copyPropertyList(cls, &property_count));
for (size_t i = 0; i < property_count; ++i) {
objc_property_t property = properties[i];
if (!IsRetained(property))
continue;
[ValueOf(self, property) release];
}
}
} // namespace details
} // namespace mac
} // namespace base