OC語言基礎筆記

OC方面的基礎筆記:


1.類的基本用法
#import <Foundation/Foundation.h>
// 大體上就是include, 用於包含頭文件, 但是即使頭文件中, 沒有ifndef defined endif, 仍然能夠踢除重複包含的頭文件
// ----@interface section----
// OC中聲明和實現是分離的, 兩個都必須有.
@interface Fraction : NSObject {    // @interface 類名: 父類名字
// 在這裏聲明成員變量, 在OC中稱爲字段, 描述類的對象的屬性
// 只有成員變量需要在外部提供接口, 或者是需要被繼承的時候, 才需要在.h文件中定義成員變量, 其他情況下只需要在.m文件中, 聲明全局變量即可
   int _numerator;    // 在類內一律使用成員變量, 在類外使用屬性
   int _denominator;
}
@property (nonatomic, assign) int numerator, denominator;
-(void) setNumerator: (int) n;        // 聲明方法
-(void) setNumerator: (int) n andDenominator: (int) d;
-(Fraction *) init;    // 或者使用-(id) init; OC中只要是以init開頭的都是構造函數, 可以帶參數
@end

// ---@implementation section----方法的實現---實例方法(以-號開頭)----類方法(以+號開頭)
@implementation Fraction        // @implementation 類名
@synthesize numerator = _numerator, denominator = _denominator;
-(void) setNumerator: (int) n andDenominator: (int) d;
{
  _numerator = n;
  _denominator = d;
}
-(Fraction *) init
{
  if (self = [super init]){
  // super是指向父類的指針, super的值和self一樣, Fraction中不僅有自己的成員變量, 還有父類中的內容, 因此初始化的時候, 要先初始化父類的內容, 然後再初始化自己本身的內容.
   _numerator = _denominator = 0;
  }
  return self;        // self是當前對象的地址, 也相當於一個成員變量
}

@end

// ---- program section ----主函數部分

int main (int argc, const char * argv[])
{

   @autoreleasepool {            // 爲自動釋放池在內存中保留了空間

       Fraction *myFraction = [[Fraction alloc] init];        // 聲明一個類的對象,分配內存空間並初始化
   // OC不允許類的對象創建在棧裏, 自己寫的類的對象只能創建在堆裏
       // [Fraction alloc]這個表達式創建一個Fraction的對象在堆空間,表達式的值是該對象的地址, myFraction只是對象的指針
                           // 或者使用 Fraction *myFraction = [Fraction new];
       [myFraction setNumerator: 1];       // 把消息發送給對象,調用setNumerator方法,傳遞一個參數爲1.
   // 調用myFraction指向的對象的方法setNumerator,
       // 對象的地址(不是指針)調用對象的方法, (地址是常量, 指針是變量)
       // 也叫做給對象發送setNumerator消息

     // OC完全兼容C; OC有自己專用的字符串, 同時也兼容C的字符串    
       NSLog(@"The value of myFraction is: ");      // 顯示, @表示NSString型字符串對象, 不加爲普通字符串    
   }
   return 0;
}

2.不可變字符串
   OC的字符串是一個對象, 它的類型是NSString類.
   OC所以會使用自己專有的字符串, 因爲這個字符串是個對象, 有很多的方法, 比外來函數如strlen等更方便, 更面向對象.
   NSString * str = @"Hello World!";
   // @"Hello World!"這個表達式表示在只讀數據段裏, 創建了一個NSString的對象, 內容是Hello World!, 表達式的值是該對象的地址, 只有字符串可以這樣創建一個對象
  // NSString的對象是不可變的
  // NSMutableString的對象是可變的

  NSString * str2  = [[NSString alloc] initWithString: str];

  NSString * str3 = [[NSString alloc] initWithUTF8String:"HEllo World!"];
  //用C的字符串創建OC的字符串, 完成C的字符串轉換成OC的字符串
  char * cString = [@"Objective-C String" UTF8String];        // 將OC字符串轉換爲C字符串

  NSString * str4 = [[NSString alloc] initWithFormat:@"hello %c %d %f", 'A', 3, 3.14];
  // 根據格式符, 拼接創建一個字符串, 最強大

  還有類方法[NSString stringWithString: str];
      [NSString stringWithUTF8String:"hello"];
      [NSString stringWithFormat:@"hello %d", 5];

 characterAtIndex
 length        // 沒有尾0

 轉換大小寫:
   uppercaseString        // 全大寫
   lowercaseString        // 全小寫
   capitalizedString    // 單詞首字母大寫
 比較大小:
    isEqualToString
    compare
    hasPrefix:        // 是否包含前綴
    hasSuffix:        // 是否包含後綴

 查找:
    rangeOfString           查找字符串中子串的範圍, range.location  range.length

 提取子串:
    subStringToIndex
    subStringFromIndex
    subStringWithRange

 結構體的對象能存儲在棧裏, 而類的對象不能存儲在棧裏.

3. 可變字符串
  NSMutableString : NSString
  NSString 的方法 NSMutableString 也能用
  傳參的時候可以傳NSString * 也可以傳 NSMutableString *

  setString  設置或替換當前字符串內容  

  增:
      追加: appendString      appendFormat
      插入: insertString:  atIndex:
  刪:
   deleteCharactersInRange
   生成range的函數NSMakeRange(2, 4);
  改:
   replaceCharactersInRange:  withString:
  查:
   rangeOfString

4.類別
  只有OC纔有類別  (categoryName)
  類別就是類的升級補丁, 可以被繼承
  類別不能用來添加成員變量, 只能添加方法(包括類方法和成員方法)

5.不可變數組
  數組的元素是任意的對象, 不僅僅侷限於字符串, 數組中只裝了對象的地址. 相當於指針數組.
  和C中的數組不同, 元素可以是不同類型的對象, 在結構上講, 它是一個鏈表.
  initWithObjects

  使用%@打印的都是對象, 而且這個類都要有一個description方法
  -(NSString *) description;        // description方法只能這樣寫, 打印的是該方法的返回值, 對中文支持不好

  直接遍歷:
   NSLog(@"%@", arrayName);
  枚舉法遍歷:  
   用當前數組創建一個枚舉器(NSEnumerator *)enumerator = [array objectEnumerator], 然後調用枚舉器的nextObject方法, 返回數組中每個元素的地址.
  快速枚舉法:
   for (id obj in arrayName){}    
   專門用於枚舉數組的for, 和平常的for不是一個. 每次循環得到一個數組元素的地址.
  循環遍歷:    
   objectAtIndex:    // 返回數組中一個元素的地址    
   indexOfObject:    // 某元素的下標    
      count        // 元素個數

  [array containsObject: ]    // array中是否包含某個元素    

  componentsJoinedByString:    // 將數組中的元素組合起來
  componentsSeparatedByString:    // 分割字符串
  componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString: ]    // 使用字符分割字符串

6.可變數組
  初始化:
    initWithArray
    [arrayName  ObjectsAtIndexes]
    setArray

  枚舉法遍歷的時候不允許修改其中的元素及個數和順序, 快速枚舉法也不可以, 但是逆序枚舉的時候reverseObjectEnumerator可以修改

  增加:
    addObject
    insertObject:  atIndex:        

  刪除:
    removeObjectAtIndex
    removeObject

  exchange   replace

  排序:
    sortUsingSelector: @selector(isBigThan:)    // selector叫做選擇器, 相當於成員方法的函數指針

7.SEL
 SEL是一個類型, 用SEL聲明的一個變量, 裏面裝的是消息, 如: SEL s = @selector(methodName);  // 有參數要寫:, 即完整的方法名
 @selector實際上返回的是名字ID; 作用是使方法可以賦值, 因此就可以傳參, 即可以作爲函數的參數來使用
 編譯器給每一個方法都分配了一個編號(0, 1, …), 叫名字ID, 不同的類中, 只要方法的名字相同, 名字ID就相同, 不同的是每個方法的入口地址不一樣
 [objectName performSelector: s withObject: ]    // 還原方法, 並調用, 有1個參數, 就加1個withObject, 最多支持2個
 repondesToSelector:@selector()   //對象能否響應selector指定的方法

8.Class
 Class也是一個類型, 是裝類的變量, 如: Class cls = [ClassName class];   之後就可以用cls代替ClassName
 作用是使類可以賦值, 因此就可以傳參, 用於isKindOfClass: [ClassName class]    // 是否是ClassName類或其子類
 isSubclassOfClass:[ClassName class]

9.字典
  NSMutableDictionary: NSDictionary
  initWithObjectsAndKeys:
  // 字典中的成員稱爲鍵值對, @"One"和@"1"組成一個鍵值對, @"One"稱爲值(Value), @"1"稱爲鍵(Key);
  // 鍵和值都是任意對象, 不過, 鍵往往使用字符串, 字典裏裝的只是鍵和值的地址, 值可以重複, 但是鍵不能重複, 爲同一個key設置value時, 將會替換掉原始的value
  // 字典中的鍵值對沒有順序, 沒有第一個第二個之說, 和數組不一樣, 結構上也是鏈表
  ObjectForKey        // 可以迅速通過key來找到一個值(value)
  count            // 鍵值對的個數
  枚舉法遍歷有兩種, 通過鍵枚舉遍歷(keyEnumerator), 通過值枚舉遍歷[objectEnumerator], 快速枚舉法, 遍歷到的是鍵,
  setObject: forKey:    
  removeObjectForKey

10.setter, getter, @property
  在setter, getter中, 可以使用.運算符, 如果是賦值, 是使用set方法, 如果是使用私有變量, 是使用get方法
  @property (readonly)    // 表示只創建get方法, 不創建set方法, 沒有write only
  (atomic)    // 原子操作, 有這個參數時, 在這個線程運行結束之前, 不允許其他線程使用我已用的資源, 正常情況下, 線程是可以使用同一個資源, 並且多個線程間可以交替的運行
  (nonatomic)    // 不必原子操作, 默認是原子操作的, 因此有時會加這個參數
  @property (getter = OtherName) int name; // 修改默認的getter名字name爲OtherName, 使用的時候可以同時使用這兩個名字
  @property (setter = setOther:)       // setter後面必須有冒號;
  (assign) 和 (readwrite) 都是默認的屬性, 不需要寫, 有時寫上assign, 表示其他屬性都不需要, 而不是忘記寫了其他屬性
  // 如:@property NSString * name; 這時會有錯誤, 寫成@property (assign) NSString * name; 就沒有錯誤了
  // 多個屬性之間, 使用逗號隔開
  (copy)  (retain)    // 這樣聲明對象的時候, 要在dealloc中加入release.
  // NSString使用copy, 其他的對象都用retain, 基本數據類型都是默認的assign

11.繼承
  多態: 同一名字的方法, 做不同的事情, 有重載, 重寫, 虛函數
  封裝: 把複雜的功能, 封裝成相對簡單的代碼, 如函數, 宏, @property, 結構體, 類
  private: 不能被子類繼承, 不能被外部函數訪問, 但是繼承的時候, 子類也給private分配了空間,
  protected: 能被子類繼承, 不能被外部函數訪問
  public: 可以被子類繼續, 可以被外部函數訪問
  C++繼承時的方式也有三種, 但是和變量的權限完全不一樣. private繼承, 繼承來的成員, 都變成私有的; protected繼承, 繼承來的成員, 都變成受保護的; public繼承, 繼承來的成員, 原本是什麼權限, 還是什麼權限.
  OC中只有公有繼承, 子類繼承之後, 多了一些變量, 就叫做派生, 子類的成員分爲繼承和派生兩部分.
  繼承的時候是完整的繼承了父類的全部, 使用繼承自父類的方法, 可以去訪問父類的私有成員, 雖然子類中沒有父類的私有成員, 但確爲其分配了空間

  NSString, NSArray, NSDictionary這三個類不能被程序員自己繼承

  虛函數: OC中的所有成員方法都是虛函數,
   1) 父類的指針可以指向子類的對象
   2) 調用方法時, 不看指針只看對象
  不同事物被同一事件觸發, 產生不同的響應

12.
棧: (函數, 結構, 變量等存儲的地方)
堆:
數據段:
只讀數據段:
代碼段: (告訴cpu做什麼, 然後在棧裏面開始做)(函數等結構的入口地址都是在代碼段的, 實體是存儲在棧中的)
  壓棧

13.內存管理
  就是堆空間的創建和釋放問題, C語言在釋放堆的時候, 有不足, 因此OC有自己的內存管理
  給一個對象分配一個堆, 只是將這處堆空間設爲私有的, 將這處對象釋放後, 將這處堆空間設爲公有的, 但堆中存儲的內容還存在, 沒有丟失, 除非之後再給這個堆空間覆蓋(重新賦值).
  C語言中不釋放會發生內存泄露, 釋放兩次, 會出現重複釋放, free(p)的時候, 釋放的是p指向的堆空間, C中也有類似於OC的計數器, 叫PV操作(加減操作), 不過需要自己寫計數器, 和釋放函數
  alloc時, 自動將計數器設爲1, retain計數器加1, release減1, retainCount查看引用計數
  內存管理黃金法則:
     1.(公認) 當使用alloc, retain, copy, mutableCopy, new "創建"一個對象, 或增添一個指針, 則必須使用release或autorelease進行"釋放".
     2.(非公認) 每個指針做自己的內存管理, 每個類做自己的內存管理, 各人顧各人.

  放在只讀數據段中的對象, 計數器被設置爲負數(-1), retain遇見負數的時候, 什麼也不會做, 不修改計數器, 因爲只讀數據段不能被修改
  -(void)dealloc; 析構方法, 沒有參數, 不能重載  
  常量字符串的set方法, if (name != newName){ [name release]; name = [newName retain];}, 之後還要在dealloc中加入[name release]; [super dealloc];  

  autorelease, 將使用autorelease的對象放入最近的自動釋放池中, 等池釋放的時候, 才釋放對象; 原則上, 除非萬不得已, 不要使用autorelease. 在類方法中, 一般都是使用autorelease; 在get對象時, 最好也要使用, return [[name retain] autorelease];
  IOS系統下, 每個觸發週期, 都會創建並釋放一個自動釋放池
  還有一種就是ARC(自動管理內存)                  

14.協議
  協議是完成兩個類之間通信的一種機制, 在兩個類的對象之間傳遞信息.
  發送方持有協議, 接收方遵守協議.
  @protocol    <protocolName>       id <protocolName> delegateName;
  @required     // 遵守協議的類必須實現該方法, 默認的屬性
  @optional    // 可選的
  協議中聲明過的方法, 遵從協議的類可以不寫聲明, 直接寫實現
  如果兩個對象互爲代理, 即互爲引用, 若都計數, 會發生死鎖; 所以當兩個對象互爲代理的時候, 若A->p = [B retain],(A對B強引用), 那麼B->p = A,(B對A弱引用) 不要再計數.
  單向協議的時候, 如果協議沒有單獨放在一個文件中, 協議要放在發送方所在的協議中, 因爲發送方有可能是接收方的成員, 如果協議放在接收方中, 頭文件包含會形成一個環.
 conformsToProtocol:@protocol()

15.文件
1)關於文件本身的操作 (NSFileManager 文件管理器)
  [NSFileManager defaultManager]    // 聲明一個NSFileManager對象
  [contentsOfDirectoryAtPath: error: &error]    // 淺度遍歷, 查看當前目錄下的內容, 返回值是數組; 如果沒有錯誤, error返回nil, 否則, 會在堆中創建個NSError的對象, 並將該對象地址賦給error; 傳地址, 就是爲了修改地址中存的值
  [subpathsOfDirectoryAtPath: error: &error]    // 深度遍歷, 不僅遍歷當前目錄的文件, 也遍歷子目錄下的內容
  createDirectoryAtPath: withIntermediateDirectories: NO attributes: nil error: &error];
  // 創建一個目錄; 第二個參數, 如果傳入YES, 會自動創建中間目錄(mkdir -p), 如果傳入NO, 只要中間目錄不存在, 就報錯; 第三個參數, 設置該目錄的屬性, 傳入nil, 爲一般(默認缺省)屬性;
  createFileAtPath: contents: attributes:     // 創建文件
  字符串自帶一個dataUsingEncoding:  將一個字符串存入NSData中, data.bytes讀取data中的內容
  removeItemAtPath: error:&error        // 刪除文件或目錄
  copyItemAtPath: toPath: error:        // 拷貝, 文件名必須寫全
  attributesOfItemAtPath: error:        // 獲得文件屬性, 放在字典中
  fileExistsAtPath:                // 判斷文件是否存在
  fileExistsAtPath: isDirectory:        // 判斷文件是否存在, 並且是否是文件夾

2)關於文件內容的操作 (NSFileHandle 文件句柄)
  從文件到內存是讀, 從內存到文件是寫
  file pointer(指針)文件指針    file descriptor(數字)文件描述符    file handle(對象)文件句柄, 往文件句柄裏寫就是往文件中寫
  [NSFileHandle fileHandleForReadingAtPath: ]    // 以只讀的方式打開文件生成文件句柄
  readDataToEndOfFile
  readDataOfLength    // read讀兩次的時候, 不是從頭再開始讀, 而是每次讀都接着上次讀到的位置往下讀
  字符串的方法: initWithData: encoding    // data轉字符串    dataUsingEncoding: // 字符串轉data
  fileHandleForWritingAtPath:  // 以只寫的方式打開文件, 如果文件不存在, 則創建文件, 在C中"w"會清空原文件, OC是一個一個的覆蓋
  writeData:         // 第一次從頭開始寫, 第二次接着往下寫
  seekToEndOfFile    // 將讀寫指針置到文件尾
  seekToFileOffset:    // 將讀寫指針置到文件指定位置, 0就是文件首
  truncateFileAtOffset:  // 清空(截斷)一個文件, 只剩下前面n個字節
  fileHandleForUpdatingAtPath:        // 讀寫操作

16.NSDate
  NSDate * date = [NSDate date];    // 使用當前時間創建一個date對象
  [NSDate dateWithTimeIntervalSinceNow: seconds]    // 用一個時間間隔(seconds)來表示過去或未來的某一時間
  [[NSDate date] timeIntervalSinceDate: date]        // 將日期與保存在date中的日期進行比較  
  [NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow: ]];    // 讓應用程序休眠一段時間

  NSDateFormatter    // 將日期轉化爲完全格式化的字符串
  dateFormatter.dateFormat = @"MM/dd/YY HH:mm:ss";
  [dateFormatter stringFromDate: [NSDate date]];

  [NSTimer scheduledTimerWithTimeInterval: 1 target: self selector: @selector() userInfo: nil repeats: YES]  
  // 1秒後觸發此定時器, 並不斷循環下去, 直到定時器被禁用([timer invalidate])

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章