面試技巧攻克-Objective-C語言

一、語言基礎(chǔ)

1、#import和#include,@class有什么區(qū)別?

import不會(huì)重復(fù)引入頭文件

@class是向前聲明,告訴編譯器有這么一個(gè)類的定義,但是暫時(shí)不引入,保證編譯可以通過,直到運(yùn)行時(shí)采取查看類的實(shí)現(xiàn)文件。這樣也可以避免重復(fù)引用甚至循環(huán)引用等問題。

2、#import<>和#import“”有什么區(qū)別?

import<>只會(huì)去系統(tǒng)目錄下尋找
import“”會(huì)先去用戶目錄下尋找,如果找不到,會(huì)繼續(xù)去系統(tǒng)目錄下尋找

3、Objective-C中堆和棧有什么區(qū)別?

堆一幫用來存放oc對(duì)象,需要手動(dòng)申請(qǐng)和釋放內(nèi)存,ARC環(huán)境下由編譯器管理,不需要手動(dòng)管理。
棧由系統(tǒng)自動(dòng)分配,一般存放非oc對(duì)象的基本類型數(shù)據(jù),例如int,float,不需要手動(dòng)管理。

4、self和super有什么區(qū)別?為什么要使用[super init]?

self是一個(gè)類的隱藏參數(shù),指向當(dāng)前實(shí)例對(duì)象,super是編譯器標(biāo)識(shí)符,在運(yùn)行時(shí),self和super指向同一個(gè)實(shí)例對(duì)象。
區(qū)別在于:當(dāng)self調(diào)用方法時(shí),會(huì)優(yōu)先在當(dāng)前類的方法列表中尋找方法,當(dāng)使用super調(diào)用方法時(shí),會(huì)優(yōu)先從父類的方法列表中尋找方法。

子類初始化時(shí),調(diào)用[super init]方法,主要是為了避免造成未知的錯(cuò)誤,如果父類初始化不成功,返回nil,可以根據(jù)父類初始化結(jié)果,做響應(yīng)容錯(cuò)處理。

二、屬性和實(shí)例變量

1、屬性和實(shí)例變量的區(qū)別是什么?

使用實(shí)例變量的方式聲明的變量,只能在類內(nèi)部訪問,類外無法訪問,而且不能使用“.”語法訪問變量,如果需要對(duì)外提供訪問能力,需要手動(dòng)實(shí)現(xiàn)set和get方法。
使用屬性的方式聲明的變量,編譯器會(huì)自動(dòng)生成set和get方法,也就可以使用“.”語法訪問變量。如果屬性是聲明在h文件中,類內(nèi)部和外部都可以訪問這個(gè)變量,如果是聲明在m文件中,則只能當(dāng)前類內(nèi)部訪問,外部包括子類都無法訪問。

2、修飾屬性的關(guān)鍵字有哪些,分別有什么作用?

修飾屬性的關(guān)鍵字有以下幾個(gè)
(1)原子性:nonatomic,atomic
(2)讀寫控制:readonly,readwrite,getter,setter
(3)內(nèi)存管理:assign,retain,weak,strong,copy,__unsafe_unretained

原子性(nonatomic,atomic)

在多線程中,同一個(gè)變量被多個(gè)線程同時(shí)訪問,會(huì)造成數(shù)據(jù)污染,因此為了安全,Objective-C中默認(rèn)屬性為atomic,即對(duì)set方法加鎖,保證多線程下數(shù)據(jù)安全。同樣的也會(huì)為此承擔(dān)一部分的資源開銷。應(yīng)用中不是特殊情況(多線程通信)一般屬性聲明為nonatomic,這樣可以提高訪問時(shí)的性能。

讀寫控制(readonly,readwrite,getter,setter)

readonly標(biāo)識(shí)只讀,編譯器只提供get方法
readwrite標(biāo)識(shí)讀寫,編譯器提供set和get方法
getter和setter用來指定存取方法

內(nèi)存管理(assign,retain,weak,strong,copy)

assign可以修飾oc對(duì)象和和oc對(duì)象的基礎(chǔ)類型,標(biāo)識(shí)簡單賦值,指針弱引用,不會(huì)對(duì)引用計(jì)數(shù)+1
weak修飾弱引用,只能修飾oc對(duì)象,和assign相同,不同的是,weak修飾的變量在銷毀后,自動(dòng)將指針置為nil,避免野指針。
retain修飾oc對(duì)象,為了持有對(duì)象,聲明強(qiáng)引用,引用計(jì)數(shù)+1。
strong和reatin類似,在ARC中,用strong代替retain。
copy建立一個(gè)和原有對(duì)象內(nèi)容相同且引用計(jì)數(shù)為1的新的對(duì)象。

3、什么時(shí)候使用weak關(guān)鍵字?和assign有什么區(qū)別?

(1)ARC中為了避免循環(huán)引用,可以讓其中一個(gè)對(duì)象使用weak修飾,常見“delegate,block”
(2)Interface Builder中IBOutlet修飾的控件一般也使用weak
區(qū)別:weak只能修飾oc對(duì)象,并且在銷毀后自動(dòng)將指針置為nil,避免野指針,而assign可以修飾oc對(duì)象和非oc對(duì)象的基礎(chǔ)類型數(shù)據(jù),當(dāng)對(duì)象銷毀后,不會(huì)將指針置為nil,形成野指針,再次調(diào)用時(shí)會(huì)導(dǎo)致崩潰。

4、nonatomic和atomic有什么區(qū)別?atomic是絕對(duì)的線程安全么?如果不是該如何實(shí)現(xiàn)?

區(qū)別:對(duì)屬性的存取操作是否添加加鎖操作,來保證多線程下數(shù)據(jù)存取的安全性。在執(zhí)行效率上nonatomic比atomic存取效率更高。

絕對(duì)線程安全么?不是絕對(duì)安全,可以保證大部分情況下數(shù)據(jù)讀取的一致性,比如在多線程下,兩個(gè)線程都對(duì)屬性進(jìn)行循環(huán)+1操作,導(dǎo)致對(duì)屬性的操作,變?yōu)樽x取,+1,存儲(chǔ)的三個(gè)操作,而atomic只能保證讀取和存儲(chǔ)操作,無法保證+1操作時(shí)的原子性。

如何保證絕對(duì)線程的安全?其實(shí)只要給線程中執(zhí)行的代碼塊加鎖就能實(shí)現(xiàn)多線程訪問的安全。

三、實(shí)例方法和類方法

1、什么是類工廠方法?

簡單的說就是用來快速創(chuàng)建對(duì)象的的類方法,可以直接返回一個(gè)初始化好的對(duì)象。UIKit中最經(jīng)典的就是UIButton類中的buttonWithType:類工廠方法。
特征:
(1)一定是類方法
(2)返回值一定是id/instancetype類型
(3)規(guī)范的類方法名,一般以小寫類名為開頭

2、OC中有方法重載么?

沒有,因?yàn)楹瘮?shù)語法定義的問題,OC編譯器不允許定義函數(shù)名相同,參數(shù)個(gè)數(shù)相同,但是返回類型和參數(shù)類型不同的方法。

四、數(shù)據(jù)類型和運(yùn)算符

1、OC中NSInteger和int基礎(chǔ)數(shù)據(jù)類型有什么區(qū)別?

NSInteger是long 和 int 的別名,在預(yù)編譯階段,NSInteger會(huì)根據(jù)系統(tǒng)是32位的還是64位的來動(dòng)態(tài)確定是int類型還是long類型,NSInteger也是官方推薦使用的基本數(shù)據(jù)類型。

2、instancetype和id有什么區(qū)別?

instancetype和id都可以指向任意OC對(duì)象,不同的是:
(1)id可以作為返回值,形參,變量,并將對(duì)象的確定延遲到運(yùn)行時(shí)。
(2)instancetype只能作為返回值,并且在預(yù)編譯時(shí)已經(jīng)確定類型。

五、繼承和多態(tài)

1、OC中有多繼承么?

OC中沒有多繼承,但是可以通過組合,協(xié)議,分類實(shí)現(xiàn)類似多繼承。

2、OC為什么不能實(shí)現(xiàn)多繼承?

因?yàn)镺C的消息機(jī)制,名字查找發(fā)生在運(yùn)行時(shí),而不是編譯時(shí),不能解決多個(gè)基類的二義性。

六、分類和擴(kuò)展

1、什么是Category?作用什么?

Category是OC在不破壞已有類的情況下,為該類添加新方法的一種方式。

作用:
(1)對(duì)現(xiàn)有類添加方法
(2)在沒有源代碼的情況下,對(duì)類進(jìn)行擴(kuò)展
(3)將類中方法的實(shí)現(xiàn)分散到不同文件中,減小單個(gè)文件體積
(4)可以按需動(dòng)態(tài)加載不同的Category

特性:
(1)重名的情況下,類別中的方法優(yōu)先級(jí)高于原類中的方法
(2)不能直接添加成員變量(可以使用runtime實(shí)現(xiàn),較為復(fù)雜)
(3)同一個(gè)類的不同類別聲明了相同方法,調(diào)用時(shí)不確定
(4)可以添加屬性,但是不會(huì)生產(chǎn)set和get 方法,需要通過關(guān)聯(lián)對(duì)象實(shí)現(xiàn)

2、Category的實(shí)現(xiàn)原理是什么?為什么只能添加方法,不能添加屬性?

(1)先看一下Category在runtime源碼中,Categroy定義為一個(gè)結(jié)構(gòu)體

//分類的定義,結(jié)構(gòu)體
typedef struct category_t {
    const char *name;//分類名
    classref_t cls;//擴(kuò)展的類
    struct method_list_t *instanceMethods;//實(shí)例方法列表
    struct method_list_t *classMethods;//類方法列表
    struct protocol_list_t *protocols;//協(xié)議列表
    struct property_list_t *instanceProperties;//屬性列表
} category_t;

從Category的定義里可以看出,分類可以添加實(shí)例方法,類方法,實(shí)現(xiàn)協(xié)議,添加屬性,而不能添加實(shí)例變量,因?yàn)闆]有存儲(chǔ)實(shí)例變量列表的指針。

Category是如何加載的?
(1)_objc_init runtime入口函數(shù),初始化
(2)map_images 加鎖
(3)map_images_nolock 完成類的注冊(cè),初始化,及l(fā)oad方法加載
(4)_read_images 完成類的加載,協(xié)議的加載,類別的加載等工作
(5)remethodizeClass 這一步非常關(guān)鍵,它將類別綁定到目標(biāo)類上
(6)attachCategories 這是最重要的一步,將類別中的方法,屬性綁定到目標(biāo)類
(7)attachLists 將目標(biāo)類中的方法和分類中的方法放到一個(gè)列表中

_read_images具體作用:將類別和目標(biāo)類綁定,并重建目標(biāo)類的方法列表
attachCategories具體作用:分配一個(gè)新的列表空間,用來存放類別的實(shí)例方法,類方法,協(xié)議方法,交給attachLists處理
attachLists具體作用:創(chuàng)建一個(gè)新的列表,與類別中傳過來的列表融合在一起,變成新的方法列表。
如果有重名的方法,類別中的方法位置更靠前,類方法位置靠后,也就解釋了為什么類別的方法優(yōu)先級(jí)要高于目標(biāo)類的方法。

需要注意的是:盡管Category定義中有存放屬性的變量,但是源碼實(shí)現(xiàn)中,并不會(huì)為屬性生成set和get方法,所以需要借助關(guān)聯(lián)對(duì)象,來手動(dòng)實(shí)現(xiàn)。

3、關(guān)聯(lián)對(duì)象是怎么實(shí)現(xiàn)的?

翻一下runtime的源碼,在objc-references.mm文件中有個(gè)方法_object_set_associative_reference:


void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
    // retain the new value (if any) outside the lock.
    ObjcAssociation old_association(0, nil);
    id new_value = value ? acquireValue(value, policy) : nil;
    {
        AssociationsManager manager;
        AssociationsHashMap &associations(manager.associations());
        disguised_ptr_t disguised_object = DISGUISE(object);
        if (new_value) {
            // break any existing association.
            AssociationsHashMap::iterator i = associations.find(disguised_object);
            if (i != associations.end()) {
                // secondary table exists
                ObjectAssociationMap *refs = i->second;
                ObjectAssociationMap::iterator j = refs->find(key);
                if (j != refs->end()) {
                    old_association = j->second;
                    j->second = ObjcAssociation(policy, new_value);
                } else {
                    (*refs)[key] = ObjcAssociation(policy, new_value);
                }
            } else {
                // create the new association (first time).
                ObjectAssociationMap *refs = new ObjectAssociationMap;
                associations[disguised_object] = refs;
                (*refs)[key] = ObjcAssociation(policy, new_value);
                _class_setInstancesHaveAssociatedObjects(_object_getClass(object));
            }
        } else {
            // setting the association to nil breaks the association.
            AssociationsHashMap::iterator i = associations.find(disguised_object);
            if (i !=  associations.end()) {
                ObjectAssociationMap *refs = i->second;
                ObjectAssociationMap::iterator j = refs->find(key);
                if (j != refs->end()) {
                    old_association = j->second;
                    refs->erase(j);
                }
            }
        }
    }
    // release the old value (outside of the lock).
    if (old_association.hasValue()) ReleaseValue()(old_association);
}

我們可以看到所有的關(guān)聯(lián)對(duì)象都由AssociationsManager管理,而AssociationsManager定義如下:


class AssociationsManager {
    static OSSpinLock _lock;
    static AssociationsHashMap *_map;               // associative references:  object pointer -> PtrPtrHashMap.
public:
    AssociationsManager()   { OSSpinLockLock(&_lock); }
    ~AssociationsManager()  { OSSpinLockUnlock(&_lock); }
 
    AssociationsHashMap &associations() {
        if (_map == NULL)
            _map = new AssociationsHashMap();
        return *_map;
    }

AssociationsManager里面是由一個(gè)靜態(tài)AssociationsHashMap來存儲(chǔ)所有的關(guān)聯(lián)對(duì)象的。這相當(dāng)于把所有對(duì)象的關(guān)聯(lián)對(duì)象都存在一個(gè)全局map里面。而map的的key是這個(gè)對(duì)象的指針地址(任意兩個(gè)不同對(duì)象的指針地址一定是不同的),而這個(gè)map的value又是另外一個(gè)AssociationsHashMap,里面保存了關(guān)聯(lián)對(duì)象的kv對(duì)。
而在對(duì)象的銷毀邏輯里面,見objc-runtime-new.mm:

void *objc_destructInstance(id obj) 
{
    if (obj) {
        Class isa_gen = _object_getClass(obj);
        class_t *isa = newcls(isa_gen);
 
        // Read all of the flags at once for performance.
        bool cxx = hasCxxStructors(isa);
        bool assoc = !UseGC && _class_instancesHaveAssociatedObjects(isa_gen);
 
        // This order is important.
        if (cxx) object_cxxDestruct(obj);
        if (assoc) _object_remove_assocations(obj);
 
        if (!UseGC) objc_clear_deallocating(obj);
    }
 
    return obj;
}

runtime的銷毀對(duì)象函數(shù)objc_destructInstance里面會(huì)判斷這個(gè)對(duì)象有沒有關(guān)聯(lián)對(duì)象,如果有,會(huì)調(diào)用_object_remove_assocations做關(guān)聯(lián)對(duì)象的清理工作。

4、Category中有+load方法么?什么時(shí)候調(diào)用的?load方法可以繼承么?

load方法是不可以繼承的,因?yàn)閘oad方法不是通過消息傳遞(_objc_msgSend)方式調(diào)用的,是直接通過函數(shù)指針調(diào)用的。因此load方法不存在類的層級(jí)遍歷。
Category中也有l(wèi)oad方法,和類中l(wèi)oad方法不同的是,它不是簡單的繼承或者覆蓋,而是獨(dú)立的load方法。和類中的load方法沒有關(guān)系。

在runtime加載時(shí)調(diào)用load方法,調(diào)用順序:父類,子類,分類。

六、Block

1、Block的原理是什么?使用的時(shí)候需要注意什么?

Block是閉包,可以作為參數(shù),變量,返回值使用。在iOS中廣泛應(yīng)用,比如GCD,動(dòng)畫,循環(huán)。
通過下面一段代碼來分析一下Block原理:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int a = 10;//聲明一個(gè)變量,存在棧上
        
        void(^testBlock)(int i) = ^(int i){
            NSLog(@"a : %d",a);
            NSLog(@"i : %d",i);
        };
        
        a = 20;
        
        testBlock(a);//調(diào)用block
    }
    return 0;
}

打印結(jié)果為:a = 10,i=20
通過結(jié)果可以發(fā)現(xiàn),block具有保存變量瞬時(shí)值的特性,記錄了a修改之前的值。
通過Clang來看一下底層C語言的實(shí)現(xiàn):

clang -rewrite-objc main.m

以下為main函數(shù)C語言實(shí)現(xiàn)

//定義了block的結(jié)構(gòu)體
struct __main_block_impl_0 {
  struct __block_impl impl;//block的結(jié)構(gòu)體
  struct __main_block_desc_0* Desc;//block描述對(duì)象,
  int a;//存放變量的a的值
    
//構(gòu)造函數(shù)
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

//block大括號(hào)對(duì)應(yīng)的實(shí)現(xiàn)
static void __main_block_func_0(struct __main_block_impl_0 *__cself, int i) {
  int a = __cself->a; // bound by copy//a的值使用的是結(jié)構(gòu)體中指針指向的值,在構(gòu)造時(shí)已經(jīng)確定為10,而不是使用的是block外部變量a的地址,

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_vt_3r7qfrfs39729zxpgrbp45z40000gp_T_main_b630e6_mi_0,a);//打印輸出時(shí)使用的也是內(nèi)部變量a,并不是外部變量a或者使用a的指針,所以為10.
            NSLog((NSString *)&__NSConstantStringImpl__var_folders_vt_3r7qfrfs39729zxpgrbp45z40000gp_T_main_b630e6_mi_1,i);//i的值為參數(shù)的值,這里為20
        }

int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
        int a = 10;

        void(*testBlock)(int i) = ((void (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));

        a = 20;

        ((void (*)(__block_impl *, int))((__block_impl *)testBlock)->FuncPtr)((__block_impl *)testBlock, a);
    }
    return 0;
}

這里可以看出,__main_block_impl_0定義有一個(gè)成員變量a,用來保存構(gòu)造函數(shù)中傳入的a的值,相當(dāng)于構(gòu)造時(shí)復(fù)制了一份a的值,block執(zhí)行時(shí),使用的是block內(nèi)部成員變量a的值,而不是block外部的a的值,

仔細(xì)觀察可以發(fā)現(xiàn):struct __main_block_impl_0 其實(shí)是 對(duì) struct __block_impl impl的封裝

struct __block_impl impl的定義:

struct __block_impl {
  void *isa; 類似對(duì)象的指針
  int Flags;
  int Reserved;
  void *FuncPtr;
  }

isa類似對(duì)象的指針,指向block保存的區(qū)域:
(1)_NSConcreteStackBlock:棧區(qū)存儲(chǔ)的block
(2)_NSConcreteMallocBlock:堆區(qū)存儲(chǔ)的block
(1)_NSConcreteGlobalBlock:全局區(qū)存儲(chǔ)的block

棧block 在函數(shù)的作用域結(jié)束后,釋放
堆block在retainCount為0時(shí),釋放
全局block和程序的生命周期相同

FuncPtr指針,指向block的執(zhí)行函數(shù),即執(zhí)行大括號(hào)內(nèi)的代碼邏輯。

總結(jié)一下:Block底層是由結(jié)構(gòu)體實(shí)現(xiàn)的,block的調(diào)用是由函數(shù)實(shí)現(xiàn)的

Block使用注意事項(xiàng):

在block中使用自動(dòng)變量,無法在block中修改自動(dòng)變量的值,因?yàn)樵跇?gòu)造過程中,a的值已經(jīng)確定了。

如果要修改自動(dòng)變量的值,需要在自動(dòng)變量前加上__block修飾,全局變量和靜態(tài)變量不需要加修飾也可以在block中修改他們。

__block 修飾的自動(dòng)變量,為何能夠修改?改動(dòng)一下代碼:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        __block int a = 10;//聲明一個(gè)變量,存在棧上
        
        void(^testBlock)(int i) = ^(int i){
            NSLog(@"a : %d",a);
            NSLog(@"i : %d",i);
            a++;
        };
        
        a = 20;
        
        testBlock(a);//調(diào)用block
        NSLog(@"a = %d",21);
        
    }
    return 0;
}

結(jié)果輸出為:a = 20,i = 20 ,a = 21;
重復(fù)剛才的clang命令,會(huì)發(fā)現(xiàn),block結(jié)構(gòu)體的構(gòu)造函數(shù)傳入的是b的地址,也就是說不加修飾的話,是值傳遞,存在拷貝,而加了修飾的話,是指針傳遞,所以block內(nèi)部修改變量的話,外部也會(huì)修改.

最后再說一下block從棧復(fù)制到堆的幾種情況:
(1)手動(dòng)調(diào)用block的copy方法;
(2)將block賦給__strong修飾的對(duì)象,同時(shí)block中還要引用外部變量時(shí)
(3)將block作為函數(shù)返回值時(shí)
(4)向Cocoa框架含有usingBlock的方法或者GCD的API傳遞block參數(shù)時(shí)

2、什么是Block循環(huán)引用?如何解決循環(huán)引用?

Block中直接使用外部強(qiáng)指針會(huì)導(dǎo)致循環(huán)引用。
解決辦法:
(1)對(duì)當(dāng)前對(duì)象弱引用
(2)使用完block后,手動(dòng)將一方置為nil
(3)將外部對(duì)象作為參數(shù)傳入block
(4)使用Weak-Strong Dance方式來解決(也是使用最多的一種方式)

其他

1、OC中l(wèi)oad方法和initialize的方法有什么區(qū)別?

(1)load方法不能繼承,是通過函數(shù)指針調(diào)用,runtime運(yùn)行時(shí)調(diào)用,較早
(2)initialize方法可以繼承,是通過消息傳遞調(diào)用的,第一次收到消息時(shí)調(diào)用,較晚

2、copy方法是深復(fù)制還是淺復(fù)制?

淺復(fù)制是復(fù)制對(duì)象的指針,深復(fù)制是復(fù)制對(duì)象內(nèi)容,生成新的對(duì)象。

copy不管是深復(fù)制還是淺復(fù)制,復(fù)制出的對(duì)象都是不可變的。
mutablCopy復(fù)制的出的都是可變的。

按照容器和非容器類型,可變和不可變類型分。有如下幾種情況。

(1)容器-不可變: NSArray (copy 淺拷貝,mutableCopy深拷貝)
(2)容器-可變 :NSMutableArray (copy 深拷貝,mutableCopy深拷貝)
(3)非容器-不可變 :NSString(copy 淺拷貝,mutableCopy深拷貝)
(4)非容器-可變:NSMutableString (copy 深拷貝,mutableCopy深拷貝)

copy對(duì)可變對(duì)象,為深復(fù)制,原對(duì)象引用計(jì)數(shù)不+1,對(duì)于不可變對(duì)象是淺復(fù)制,引用計(jì)數(shù)+1,始終返回不可變對(duì)象。
mutableCopy始終是深復(fù)制,原對(duì)象引用計(jì)數(shù)不+1,始終返回可變對(duì)象。

非集合類:只有不可變對(duì)象進(jìn)行copy操作時(shí)是淺復(fù)制([immutableObject copy] // 淺復(fù)制),其他都是深復(fù)制
集合類:只有不可變對(duì)象進(jìn)行copy操作時(shí)是淺復(fù)制([immutableObject copy] // 淺復(fù)制),其他都是單層深復(fù)制
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,621評(píng)論 1 32
  • OC中的屬性 屬性(Property)是Objective-C語言的其中一個(gè)特性,它把類對(duì)象中的實(shí)例變量及其讀寫方...
    愛笑的貓mi閱讀 4,690評(píng)論 0 4
  • 1.設(shè)計(jì)模式是什么? 你知道哪些設(shè)計(jì)模式,并簡要敘述?設(shè)計(jì)模式是一種編碼經(jīng)驗(yàn),就是用比較成熟的邏輯去處理某一種類型...
    龍飝閱讀 2,294評(píng)論 0 12
  • 世界上有兩個(gè)可貴的詞 一個(gè)叫認(rèn)真 一個(gè)叫堅(jiān)持 認(rèn)真的人改變了自己 堅(jiān)持的人改變了命運(yùn)
    生活就是小說閱讀 684評(píng)論 3 8
  • 給予激勵(lì)和給予權(quán)利。對(duì)于表現(xiàn)優(yōu)秀的員工(技術(shù)型),我們給予激勵(lì)的方式,給予更高的肯定,以及物質(zhì)獎(jiǎng)勵(lì)。對(duì)于傾向管理的...
    王榕榕閱讀 273評(píng)論 0 0

友情鏈接更多精彩內(nèi)容