| // 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 |