本文源自本人的學(xué)習(xí)記錄整理與理解,其中參考閱讀了部分優(yōu)秀的博客和書籍殊者,盡量以通俗簡(jiǎn)單的語句轉(zhuǎn)述。引用到的地方如有遺漏或未能一一列舉原文出處還望見諒與指出钞支,另文章內(nèi)容如有不妥之處還望指教,萬分感謝操刀。
這篇文章源自一次關(guān)于@[].mutableCopy
和[NSMutableArray array]
區(qū)別的討論
- MRC環(huán)境下的區(qū)別:
像這種 [NSMutableArray array] 類方法烁挟,array 啥的,初始化的時(shí)候會(huì)調(diào)用 autorelease骨坑,會(huì)找合適的時(shí)機(jī)進(jìn)行釋放撼嗓,可以理解為:
-
[[[NSMutableArray alloc] init] autorelease]
半自動(dòng)管理內(nèi)存 -
@[].mutableCopy
不會(huì)調(diào)用 autorelease ,需要手動(dòng)管理內(nèi)存欢唾。
結(jié)論:推薦使用后者且警,性能更好
直接來看兩者在運(yùn)行時(shí)執(zhí)行的源碼:
@[].mutableCopy:
(void *)objc_msgSend(
(NSArray *(*)(Class, SEL, ObjectType _Nonnull const * _Nonnull, NSUInteger))(void *)objc_msgSend
(objc_getClass("NSArray"),
sel_registerName("arrayWithObjects:count:"),
(const id *)__NSContainer_literal(0U).arr, 0U),
sel_registerName("mutableCopy"));
簡(jiǎn)化后代碼
(void *)objc_msgSend(
//1. 找到NSArray 給他發(fā)送 arrayWithObjects:count:消息 ,生成一個(gè)NSArray的實(shí)例對(duì)象
objc_msgSend(
objc_getClass("NSArray"),
sel_registerName("arrayWithObjects:count:"),
__NSContainer_literal(0U).arr, 0U
),
//2. 對(duì)創(chuàng)建出來的對(duì)象發(fā)送 mutableCopy 消息,返回一個(gè)可變數(shù)組
sel_registerName("mutableCopy")
);
[NSMutableArray array]
(void *)objc_msgSend(
objc_getClass("NSMutableArray"),
sel_registerName("array")
);
sel_registerName的內(nèi)部實(shí)現(xiàn)
sel_registerName 內(nèi)部調(diào)用__sel_registerName
- selLock鎖是否可用
- 判斷方法明是否存在礁遣,不存在返回0
- 搜索這個(gè)方法是否創(chuàng)建過斑芜,如果是就直接返回,這也變相說明 @selector(selector) 同名方法的函數(shù)地址相同
- 沒有就創(chuàng)建(sel_alloc)并返回亡脸,過程中用到了條件鎖conditional_mutex
- namedSelectors :方法集合,內(nèi)部存儲(chǔ)了一個(gè)個(gè)哈希表
static SEL __sel_registerName(const char *name, bool shouldLock, bool copy) {
SEL result = 0;
if (shouldLock) {
selLock.assertUnlocked();
}else {
selLock.assertLocked()
};
if (!name) return (SEL)0;
result = search_builtins(name);
if (result) return result;
conditional_mutex_locker_t lock(selLock, shouldLock);
//從這行代碼可以看出 namedSelectors是一個(gè)集合押搪,存儲(chǔ)的元素是哈希 表;通過insert插入
auto it = namedSelectors.get().insert(name);
if (it.second) {
// No match. Insert.
*it.first = (const char *)sel_alloc(name, copy);
}
return (SEL)*it.first;
}
擴(kuò)展:
static objc::ExplicitInitDenseSet<const char *> namedSelectors;
class ExplicitInitDenseSet : public ExplicitInit<DenseSet<Value>> { };
父類是 ExplicitInit 浅碾,ExplicitInit 的成員是 DenseSet 類型;
DenseSet
/// Implement a set of hash tables based on dense probe.
/// 實(shí)現(xiàn)基于密集探測(cè)的哈希表集大州。
template <typename ValueT, typename ValueInfoT = DenseMapInfo<ValueT>>
class DenseSet : public detail::DenseSetImpl<
ValueT,
DenseMap<ValueT, detail::DenseSetEmpty,
DenseMapValueInfo<detail::DenseSetEmpty>,
ValueInfoT,
detail::DenseSetPair<ValueT>
>,
ValueInfoT>
{
using BaseT =
detail::DenseSetImpl<
ValueT,
DenseMap<ValueT,
detail::DenseSetEmpty,
DenseMapValueInfo<detail::DenseSetEmpty>,
ValueInfoT,
detail::DenseSetPair<ValueT>
>,
ValueInfoT
>;
public:
using BaseT::BaseT;
};
- 關(guān)于
DenseSetImpl
:
class DenseSetImpl {
static_assert(sizeof(typename MapTy::value_type) == sizeof(ValueT),
"DenseMap buckets unexpectedly large!");
MapTy TheMap;
template <typename T>
using const_arg_type_t = typename const_pointer_or_const_ref<T>::type;
public:
using key_type = ValueT;
using value_type = ValueT;
using size_type = unsigned;
explicit DenseSetImpl(unsigned InitialReserve = 0) : TheMap(InitialReserve) {}
DenseSetImpl(std::initializer_list<ValueT> Elems)
: DenseSetImpl(PowerOf2Ceil(Elems.size())) {
insert(Elems.begin(), Elems.end());
}
bool empty() const { return TheMap.empty(); }
size_type size() const { return TheMap.size(); }
size_t getMemorySize() const { return TheMap.getMemorySize(); }
/// Grow the DenseSet so that it has at least Size buckets. Will not shrink
/// the Size of the set.
void resize(size_t Size) { TheMap.resize(Size); }
/// Grow the DenseSet so that it can contain at least \p NumEntries items
/// before resizing again.
void reserve(size_t Size) { TheMap.reserve(Size); }
void clear() {
TheMap.clear();
}
/// Return 1 if the specified key is in the set, 0 otherwise.
size_type count(const_arg_type_t<ValueT> V) const {
return TheMap.count(V);
}
bool erase(const ValueT &V) {
return TheMap.erase(V);
}
void swap(DenseSetImpl &RHS) { TheMap.swap(RHS.TheMap); }
// Iterators.
class ConstIterator;
class Iterator {
typename MapTy::iterator I;
friend class DenseSetImpl;
friend class ConstIterator;
public:
using difference_type = typename MapTy::iterator::difference_type;
using value_type = ValueT;
using pointer = value_type *;
using reference = value_type &;
using iterator_category = std::forward_iterator_tag;
Iterator() = default;
Iterator(const typename MapTy::iterator &i) : I(i) {}
ValueT &operator*() { return I->getFirst(); }
const ValueT &operator*() const { return I->getFirst(); }
ValueT *operator->() { return &I->getFirst(); }
const ValueT *operator->() const { return &I->getFirst(); }
Iterator& operator++() { ++I; return *this; }
Iterator operator++(int) { auto T = *this; ++I; return T; }
bool operator==(const ConstIterator& X) const { return I == X.I; }
bool operator!=(const ConstIterator& X) const { return I != X.I; }
};
class ConstIterator {
typename MapTy::const_iterator I;
friend class DenseSet;
friend class Iterator;
public:
using difference_type = typename MapTy::const_iterator::difference_type;
using value_type = ValueT;
using pointer = const value_type *;
using reference = const value_type &;
using iterator_category = std::forward_iterator_tag;
ConstIterator() = default;
ConstIterator(const Iterator &B) : I(B.I) {}
ConstIterator(const typename MapTy::const_iterator &i) : I(i) {}
const ValueT &operator*() const { return I->getFirst(); }
const ValueT *operator->() const { return &I->getFirst(); }
ConstIterator& operator++() { ++I; return *this; }
ConstIterator operator++(int) { auto T = *this; ++I; return T; }
bool operator==(const ConstIterator& X) const { return I == X.I; }
bool operator!=(const ConstIterator& X) const { return I != X.I; }
};
using iterator = Iterator;
using const_iterator = ConstIterator;
iterator begin() { return Iterator(TheMap.begin()); }
iterator end() { return Iterator(TheMap.end()); }
const_iterator begin() const { return ConstIterator(TheMap.begin()); }
const_iterator end() const { return ConstIterator(TheMap.end()); }
iterator find(const_arg_type_t<ValueT> V) { return Iterator(TheMap.find(V)); }
const_iterator find(const_arg_type_t<ValueT> V) const {
return ConstIterator(TheMap.find(V));
}
/// Alternative version of find() which allows a different, and possibly less
/// expensive, key type.
/// The DenseMapInfo is responsible for supplying methods
/// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key type
/// used.
template <class LookupKeyT>
iterator find_as(const LookupKeyT &Val) {
return Iterator(TheMap.find_as(Val));
}
template <class LookupKeyT>
const_iterator find_as(const LookupKeyT &Val) const {
return ConstIterator(TheMap.find_as(Val));
}
void erase(Iterator I) { return TheMap.erase(I.I); }
void erase(ConstIterator CI) { return TheMap.erase(CI.I); }
std::pair<iterator, bool> insert(const ValueT &V) {
detail::DenseSetEmpty Empty;
return TheMap.try_emplace(V, Empty);
}
std::pair<iterator, bool> insert(ValueT &&V) {
detail::DenseSetEmpty Empty;
return TheMap.try_emplace(std::move(V), Empty);
}
/// Alternative version of insert that uses a different (and possibly less
/// expensive) key type.
template <typename LookupKeyT>
std::pair<iterator, bool> insert_as(const ValueT &V,
const LookupKeyT &LookupKey) {
return TheMap.insert_as({V, detail::DenseSetEmpty()}, LookupKey);
}
template <typename LookupKeyT>
std::pair<iterator, bool> insert_as(ValueT &&V, const LookupKeyT &LookupKey) {
return TheMap.insert_as({std::move(V), detail::DenseSetEmpty()}, LookupKey);
}
// Range insertion of values.
template<typename InputIt>
void insert(InputIt I, InputIt E) {
for (; I != E; ++I)
insert(*I);
}
};