日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【IOS学习基础】OC类的相关

發布時間:2023/12/20 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【IOS学习基础】OC类的相关 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

幾天前突然在別人的類的.m文件中看到這么一句代碼:@synthesize xxxx = _xxxx;?當時愣是沒理解啥意思,過后才緩過神來發現原來是把一些類的基礎知識忘記了,雖然不用過多去深究以前的一些舊東西,但但是既然遇到了,還是復習一下。

一、類與對象

  1.類:類是定義同一類所有屬性和方法的藍圖或原型。

  2.對象:用來描述客觀事物的一個實體,由具體的屬性和方法構成。

  3.類與對象的關系:類是用來制作無數實體(對象)的工程圖紙。

  4.類的特征:屬性

  5.類的行為:方法

二、封裝

  1.類就是封裝,封裝了屬性與方法。它是一種思想,其核心就是“暴露出必要的內容給外部用屬性方法私有,而對于內部細節,使用者不用去關心”。

  我們聲明一個Teacher類:

#import <Foundation/Foundation.h> @interface Teacher : NSObject {
  // @public 公共的NSString
*_name; //成員變量(實例變量) 默認@protected修飾(受保護的)

  /* 順帶一提:@protected、@public、@private、@package
   * @public 成員變量可以被在任何地方訪問。
   * @protected 成員變量能被聲明它的類和子類訪問(默認)
   * @private 成員變量只能在聲明它的類中訪問(默認現在用@Property關鍵字生成的成員變量是這個)
   * @package 一個@package成員變量在實現這個類的可執行文件鏡像中實際上是@public的,但是在外面就是@private。
   */ }
@end

?  ?然而,我們此時在外面根本無法訪問到這個受保護的成員變量。

  訪問該成員變量的方法:

  1> 打開上面 “@public”的注釋,在外面以"->“方式訪問

Teacher *tec = [[Teacher alloc] init]; tec->_name = @"姓名";

  2> 封裝set、get方法進行間接訪問,在.h文件中加上方法聲明,在.m文件中實現

-(void)setName:(NSString *)name; -(NSString *)getName;-(void)setName:(NSString *)name {_name = name; } -(NSString *)getName {return _name; }

  這樣,便可以在外面通過調用方法的方式來間接訪問該成員變量,其實下面講的@property關鍵字就是幫你解決了這個set、get方法的訪問

讓其在外面以"."的方式(本質上是調用set和get方法)間接訪問。

Teacher *tec = [[Teacher alloc] init]; [tec setName:@"testName"]; NSLog(@"%@",[tec getName]);

  總結一下成員變量和成員屬性:

    ①成員變量即實例變量

    ②成員屬性用于間接訪問類中的成員變量

    ③假如你想讓類的一個特性私有,只在本類訪問,就定義成成員變量;假如你想在類之外訪問該類的一個特性,你就將其定義成成員屬性。  

三、@property和@synthesize關鍵字

  1.在以前,我們經常可以看到這種類的聲明

#import <Foundation/Foundation.h>@interface Teacher : NSObject {NSString *_name; //成員變量 } @property (nonatomic,copy)NSString *name; //成員屬性@end#import "Teacher.h"@implementation Teacher@synthesize name = _name;@end

  這是在之前的編譯器特性中:

  @property幫我們聲明了name屬性的set和get方法

  @synthesize name = _name則表示對@property聲明的屬性name實現set和get方法,后面的” = _name“表示實現的時候訪問成員變量_name

  2.而現在我們為類聲明一個屬性則通常只需要一句話(我一般都用這種,方便):

@property (nonatomic,copy)NSString *name; //這里指在.h文件中聲明

  這是在新的編譯器特性中:

  @property直接幫助我們干了三件事:

    ①當該name屬性的成員變量未被指定時,會生成一個默認為_name的成員變量,但是該屬性為@private(私有的),自己寫的則是@protected(受保護的)

    ②聲明name屬性的set、get方法 ?

    ③實現name屬性的set、get方法

  注:如果你想要用自己生成的成員變量,則用之前的那種格式,在.h文件中增加一個成員變量,在.m文件中加上@synasize xxx = _xxx。

  成員變量用”_“下劃線開頭命名的好處:

    ①區分成員變量和屬性

    ②防止局部變量和成員變量命名沖突

四、關于繼承的幾句話

  1.繼承:建立類之間的關系,實現代碼的重用性,方便系統擴展。

  2.繼承是為了避免多個相似的類中相同的成員變量反復定義而延伸的一個特性。

  3.繼承有單根性與傳遞性

  4.被繼承的類稱之為父類或基類,繼承的類稱之為子類或派生類

  5.super關鍵字:self用于訪問本類成員,而super則是用于在子類中訪問父類成員 ?

五、分類catagory

  分類:①在不改變原來類的基礎上,為類增加一些方法,來對類進行一個擴展。

     ②在開發中,我們一般對都是為系統提供的類添加分類。還有就是將自己的類分模塊,將實現不同功能的方法寫在不同的分類中,一個類可以有無限個分類。

  1.分類又稱為非正式協議:NSObject類及其子類的一個類別(catagory)。

#import "Teacher.h"@interface Teacher (Log) +(void)log; @end#import "Teacher+Log.h"@implementation Teacher (Log) +(void)log
{
  NSLog(@"分類");
}
@end

  如上面所寫的分類,我們為Teacher類添加了一個分類"Teacher+Log.h",分類中聲明并實現了類方法+(void)log

  2.類的延展:匿名分類。

  在Teacher.m文件中

#import "Teacher.h"@interface Teacher () //這種寫法就是匿名分類@property (nonatomic,copy)NSString *nickName; //匿名分類中可以添加屬性,但是該屬性默認為@private,只能在本類中使用+(void)log; //聲明了一個類方法log@end@implementation Teacher@synthesize name = _name; //實現該類方法 +(void)log {NSLog(@"匿名分類"); }@end

?  接著我們調用log方法,出現如下打印

  ?

  這里證明:分類(非正式協議)會重寫本類及其類擴展(匿名分類)的方法。

  3.catagory中匿名分類允許添加屬性并會自動生成成員變量和set、get方法;但是在非正式協議中,允許你用@property聲明一個屬性,不會為你提供set、get方法以及成員變量,如果你直接使用的話,造成崩潰。如下

  1> 我為Teacher + MyProperty.h分類頭文件中增加了一個屬性nickName;

#import "Teacher.h"@interface Teacher (MyProperty)@property (nonatomic,copy)NSString *nickName;@end

  2>使用(缺少set、get方法導致崩潰)

Teacher *tec = [[Teacher alloc] init]; tec.nickName = @"nickNmae"; NSLog(@"%@",tec.nickName);// 打印 2016-01-24 16:58:13.656 分類[2002:159549] -[Teacher setNickName:]: unrecognized selector sent to instance 0x100213e10 2016-01-24 16:58:13.658 分類[2002:159549] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Teacher setNickName:]: unrecognized selector sent to instance 0x100213e10' *** First throw call stack:……

  3>如何在非正式協議(分類)中添加屬性【oc針對這一現象,提供了一個解決方案:關聯對象(Associated Object)】,在分類的.m文件中寫上如下代碼

#import "Teacher+MyProperty.h" #import <objc/runtime.h>static void *strKey = &strKey;@implementation Teacher (MyProperty)-(void)setNickName:(NSString *)nickName {objc_setAssociatedObject(self, &strKey, nickName, OBJC_ASSOCIATION_COPY); }-(NSString *)nickName {return objc_getAssociatedObject(self, &strKey); }@end

六、協議protocol

  1.有非正式協議,自然也有正式協議,protocol便是,用于聲明一大堆方法,等待實現,只要某個類遵守了某個協議,那么這個類就擁有了該協議的所有方法聲明。(注意:協議只存在.h聲明文件)其格式如下:

@protocol Teach <NSObject>
@required; -(void)teach:(NSString *)text; // 聲明了一個teach的方法,并且為必須實現,默認是@optional;@end//新建了一個名為Teach.h的協議頭文件

  2.類可以遵守協議(Teacher遵守teach協議)

    

  3.實現方法

-(void)teach:(NSString *)text {NSLog(@"老師教書"); }

  4.一個類只能繼承自一個父類(繼承的單根性),但是一個類可以遵守多份協議.

七、關聯對象(Associated Object)--擴展

  1.關聯對象類似于成員變量,但是它是在運行時被添加的。(用于解決分類中添加屬性的問題,上面已經介紹了原因,這里不做介紹)

  2.我們可以把關聯對象想象成一個OC對象,這個對象通過key連接到一個類的實例變量上。

  3.由于使用的是C接口,所以key是一個void指針(const void *)。我們還需要指定一個內存管理策略,以告訴Runtime如何管理這個對象的內存。內存管理策略選項值如下:

// 當宿主對象被釋放時,會根據指定的內存管理策略來處理關聯對象。當我們需要在多個線程中處理訪問關聯對象的多線程代碼時,這就非常有用了 typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {OBJC_ASSOCIATION_ASSIGN = 0,OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,OBJC_ASSOCIATION_COPY_NONATOMIC = 3, OBJC_ASSOCIATION_RETAIN = 01401,OBJC_ASSOCIATION_COPY = 01403 }; /* 如果指定的策略是assign,則宿主釋放時,關聯對象不會被釋放;而如果指定的是retain或者是copy,則宿主釋放時,關聯對象會被釋放。我們甚至可以選擇是否是自動retain/copy。 */

  4.使用

  1>?void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)方法:將一個對象連接到其它對象

    參數1:源對象,一般傳self.

    參數2:key,用來表示是哪一屬性的key,可能在分類中添加不止一個屬性。

    常見有三種寫法:

    ①?static void *strKey = &strKey;

    ②?static NSString *strKey = @"strKey";

    ③ static char strKey;

    參數3:關聯的對象

    參數4:關聯策略

    self對象將獲取一個新的關聯的對象anObject,且內存管理策略是自動retain關聯對象,當self對象釋放時,會自動release關聯對象。另外,如果我們使用同一個key來關聯另外一個對象時,也會自動釋放之前關聯的對象,這種情況下,先前的關聯對象會被妥善地處理掉,并且新的對象會使用它的內存

  2>?id anObject = objc_getAssociatedObject(self, &myKey)方法 ,獲取關聯的對象

  3>?objc_removeAssociatedObjects(self)方法,移除所有關聯

  5、應用(UIAlertView + Block分類,以自身為delegate監控選項按鈕點擊事件,以block作為關聯對象)

#import <UIKit/UIKit.h> typedef void(^CompleteBlock) (NSInteger buttonIndex);@interface UIAlertView (Block)// 用Block的方式回調,這時候會默認用self作為Delegate - (void)showAlertViewWithCompleteBlock:(CompleteBlock) block;@end#import "UIAlertView+Block.h" #import <objc/runtime.h>@implementation UIAlertView (Block)static char key;// 用Block的方式回調,這時候會默認用self作為Delegate - (void)showAlertViewWithCompleteBlock:(CompleteBlock)block {if (block) {//移除所有關聯 objc_removeAssociatedObjects(self);/**1 創建關聯(源對象,關鍵字,關聯的對象和一個關聯策略。)2 關鍵字是一個void類型的指針。每一個關聯的關鍵字必須是唯一的。通常都是會采用靜態變量來作為關鍵字。3 關聯策略表明了相關的對象是通過賦值,保留引用還是復制的方式進行關聯的;關聯是原子的還是非原子的。這里的關聯策略和聲明屬性時的很類似。*/objc_setAssociatedObject(self, &key, block, OBJC_ASSOCIATION_COPY);//設置delegateself.delegate = self;} [self show]; }- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {///獲取關聯的對象,通過關鍵字。CompleteBlock block = objc_getAssociatedObject(self, &key);if (block) {///block傳值 block(buttonIndex);} } /**OC中的關聯就是在已有類的基礎上添加對象參數。來擴展原有的類,需要引入#import <objc/runtime.h>頭文件。關聯是基于一個key來區分不同的關聯。常用函數:
objc_setAssociatedObject 設置關聯objc_getAssociatedObject 獲取關聯objc_removeAssociatedObjects 移除關聯
*/ //當然也可以不必這么麻煩,使用繼承同樣可以輕易做到。 @end

八、類的加載(認識兩個方法)

/*** 這兩個方法是在程序運行一開始就被調用的方法.* 我們可以利用他們在類被使用前,做一些預處理工作.* 比如我碰到的就是讓類自動將自身類名保存到一個NSDictionary中.*///而initialize是在類或者其子類的第一個方法被調用前調用。 +(void)initialize;//load方法是只要類所在文件被引用就會被調用. +(void)load;/*** 所以如果類沒有被引用進項目,就不會有load調用;* 但即使類文件被引用進來,但是沒有使用,那么initialize也不會被調用*/

九、反射

  1.反射:簡而言之就是通過類名返回類的對象(使用前導入#import <objc/runtime.h>頭文件,今天前面的關聯對象也用到這個頭文件,好像關于這個runtime要學的東西有點多,復習著一下子扒出了好多要學的新東西,- _ -,先從基礎的慢慢來吧)

// 類名返回類對象 +(NSObject *)createBean:(NSString *)className {Class tempClass = NSClassFromString(className);NSObject *obj;if (tempClass){obj = [[tempClass alloc]init];}return obj; }

  2.類名得到屬性名集合

+(NSArray *)propertyOfClass:(NSString *)className {NSMutableArray *arr = [NSMutableArray arrayWithCapacity:0];//通過類名獲得類的屬性const char *cClassName = [className UTF8String];id theClass = objc_getClass(cClassName);unsigned int outCount, i;objc_property_t *properties = class_copyPropertyList(theClass, &outCount);for (i = 0; i < outCount; i++){objc_property_t property = properties[i];NSString *propertyNameString = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];[arr addObject:propertyNameString];}return arr; }

 3.通過反射(結合KVC),通過類名、數據源、約定,我們就可以實現json字符串轉對象。

 4.具體之后三方庫學習MJExtension中NSObject + MJClass轉模型。

十、類簇

  1.類簇是Foundation框架中廣泛使用的設計模式(抽象工廠模式)。類簇將一些私有的、具體的子類組合在一個公共的、抽象的超類下面,以這種方法來組織類可以簡化一個面向對象框架的公開架構,而又不減少功能的豐富性。

  2.類簇的概念(選自百度百科。。。)

  類簇 是一群隱藏在通用接口下的與實現相關的類,使得我們編寫的代碼可以獨立于底層實現(因為接口是穩定的)。

  如創建NSString對象時,你得到的可能是NSLiteralString,NSCFString,NSSimpleCString等。即不同的NSString對象調用同一個接口A,接口A的實現可能是不同的。

  在Foundation框架中,常見的類簇有NSNumber,NSString,NSArray,NSDictionary等。 想要在類簇中創建子類會困難一些,必須是抽象超類的子類,必須重載超類的原始方法,必須聲明自己的數據存儲。最方便的是使用組合或者類別來代替子類化。
  3.關于重寫init方法時候調用父類的init方法:self = [super init]和[super init]

  咋看之下,產生了一個疑問,為什么[super init]要賦值給self。今天看了下類簇的概念,終于明白了,由于在有些情況下,init可能會改變返回的對象,這時候必須賦值給self。

  4、不推薦繼承類簇

  當你繼承某個類簇的超類之后,子類可以使用父類的方法,結果你去調用該類簇的超類的方法,你會發現程序崩潰了,原因是由于在超類的方法的實現里,你不知道它實際調用的它里面的哪一個子類的方法(這些組合的子類聲明和實現都隱藏在該超類的.m文件里面),結果你的類是直接繼承自該類簇的超類,也就是說你的類根本就不認識這個方法。

?

轉載于:https://www.cnblogs.com/silence-wzx/p/5149743.html

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的【IOS学习基础】OC类的相关的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。