iOS runtime之sel_registerName

本文源自本人的學(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

  1. selLock鎖是否可用
  2. 判斷方法明是否存在礁遣,不存在返回0
  3. 搜索這個(gè)方法是否創(chuàng)建過斑芜,如果是就直接返回,這也變相說明 @selector(selector) 同名方法的函數(shù)地址相同
  4. 沒有就創(chuàng)建(sel_alloc)并返回亡脸,過程中用到了條件鎖conditional_mutex
  5. 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);
  }
};

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市垂谢,隨后出現(xiàn)的幾起案子厦画,更是在濱河造成了極大的恐慌,老刑警劉巖滥朱,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件根暑,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡徙邻,警方通過查閱死者的電腦和手機(jī)排嫌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缰犁,“玉大人淳地,你說我怎么就攤上這事∷荩” “怎么了颇象?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)并徘。 經(jīng)常有香客問我遣钳,道長(zhǎng),這世上最難降的妖魔是什么麦乞? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任蕴茴,我火速辦了婚禮劝评,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘荐开。我一直安慰自己付翁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布晃听。 她就那樣靜靜地躺著百侧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪能扒。 梳的紋絲不亂的頭發(fā)上佣渴,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音初斑,去河邊找鬼辛润。 笑死,一個(gè)胖子當(dāng)著我的面吹牛见秤,可吹牛的內(nèi)容都是我干的砂竖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鹃答,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼乎澄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起测摔,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤置济,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后锋八,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浙于,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年挟纱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了羞酗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡紊服,死狀恐怖檀轨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情围苫,我是刑警寧澤裤园,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布撤师,位于F島的核電站剂府,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏剃盾。R本人自食惡果不足惜腺占,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一淤袜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧衰伯,春花似錦铡羡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至怎顾,卻和暖如春读慎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背槐雾。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來泰國打工夭委, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人募强。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓株灸,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親擎值。 傳聞我的和親對(duì)象是個(gè)殘疾皇子慌烧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 前言:面試筆試都是必考語法知識(shí)點(diǎn)。請(qǐng)認(rèn)真復(fù)習(xí)和深入研究OC幅恋。 目錄:iOS-面試題-OC基礎(chǔ)篇 (1) - (84...
    麥穗0615閱讀 4,258評(píng)論 0 33
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉杏死,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,715評(píng)論 0 9
  • 引導(dǎo) 對(duì)于從事 iOS 開發(fā)人員來說,所有的人都會(huì)答出「 Runtime 是運(yùn)行時(shí) 」捆交,什么情況下用 Runtim...
    Winny_園球閱讀 4,209評(píng)論 3 75
  • @synthesize和@dynamic分別有什么作用品追?@property有兩個(gè)對(duì)應(yīng)的詞玄括,一個(gè)是 @synthes...
    筆筆請(qǐng)求閱讀 515評(píng)論 0 1
  • 對(duì)于從事 iOS 開發(fā)人員來說,所有的人都會(huì)答出【runtime 是運(yùn)行時(shí)】什么情況下用runtime?大部分人能...
    夢(mèng)夜繁星閱讀 242評(píng)論 1 0