1. 程式人生 > >Object-C中對自定義類實現協議

Object-C中對自定義類實現協議

如果嘗試使用自定義類(例如,人類(person類)、地址簿類(myBook類)、分數類(Fraction類))中的copy方法,如

 myBook = [myBook mutableCopy];
 person = [Person copy];
等類似的操作,將會收到一條異常出錯的訊息,它可能如下所示:

-[Fraction copyWithZone:]: unrecognized selector sent to instance 0x7fabb8414380

這種錯誤,是對於自定義類,要實現使用自己的類進行復制,必須根據<NSCopying>協議實現其中的一兩個方法。

下面將展示如何為自定義的分數類(Fraction類)新增copy方法。注意:這裡描述的複製策略的技巧非常適合於你自己定義的類。如果這些類是任何Foundation類的子類,那麼可能需要實現較為複雜的複製策略。必須考慮這樣一個事實:超類可能已經實現了它自己的複製策略。

實現<NSCopying>協議時,類必須實現copyWithZone:方法來響應copy訊息。(這條copy訊息僅將一條帶有nil引數的copyWithZone:訊息傳送給你的類)。注意,如果想要區分可變副本和不可變副本,那麼copyWithZone:應該返回不可變副本,而mutableCopyWithZone:應該返回可變副本。產生物件的可變副本並不要求被複制的物件本身也是可變的(反之亦然),想要產生不可變副本的可變副本是很合理的(例如,字串物件)。

在Fraction.h檔案中如下所示:(其中Fraction是NSObject的子類,並且符合NSCopying協議)

#import <Foundation/Foundation.h>

@interface Fraction : NSObject<NSCopying>
{
    int a, b;
}

@property int a, b;

-(void)setTo:(int) a over: (int) b;
-(void)print;

@end

在實現檔案Fraction.m中,為新方法新增如下定義:
#import "Fraction.h"

@implementation Fraction

@synthesize a,b;

-(void)setTo:(int) aa over: (int) bb
{
    a = aa;
    b = bb;
}

-(void)print
{
    NSLog(@"%i/%i",a, b);
}

//實現NSCopying協議的方法,來使此類具有copy功能
-(id)copyWithZone:(NSZone *)zone
{
    Fraction *newFract = [[Fraction allocWithZone:zone] init];
    
    [newFract setTo:a over:b];
    
    return newFract;
}

@end

在檔案main.m中對於上述類的測試程式碼如下:

#import <Foundation/Foundation.h>
#import "Fraction.h"

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

    @autoreleasepool {

        Fraction *f1 = [[Fraction alloc] init];
        Fraction *f2;
        
        [f1 setTo:2 over:5];
        
        f2 = [f1 copy]; 
        
        [f2 setTo:1 over:3];
        
        [f1 print];
        [f2 print];
        
        [f1 release];
        [f2 release];
        
    }
    return 0;
}


由此可以實現對自定義類Fraction類的拷貝,執行結果如下:

2/5

1/3

該程式建立了一個名為f1的Fraction物件並將其設定為2/5.然後,它呼叫copy方法來產生副本,copy方法向你的物件傳送copyWithZone:訊息,這個方法產生了一個新的Fraction,將f1的值複製到其中,並返回結果。回到main函式中,再將這個結果賦值給f2.隨即,將f2中的值設定為分數1/3,這樣就驗證了這些操作對原始分數f1是沒有影響的。

如果你的類可以產生子類,那麼copyWithZone:方法將被繼承。在這種情況下,該方法中的程式行:

 //無子類是可以這樣實現
    Fraction *newFract = [[Fraction allocWithZone:zone] init];

應該改為:

//有子類時,需要這樣實現
    Fraction *newFract = [[[self class] allocWithZone:zone] init];

這樣,可以從該類分配一個新的物件,而這個類的copy的接收著(例如,如果它產生了一個名為NewFraction 的子類,那麼應該確保在繼承的方法中分配了新的NewFraction物件,而不是Fraction物件)。

如果編寫一個類的copyWithZone:方法,而該類的超類也實現了<NSCopying>協議,那麼應該先呼叫超類的copy方法以複製繼承來的例項變數,然後加入自己的程式碼以複製想要新增到該類中的任何附加的例項變數(如果有的話)。

你必須確定是否在類中實現淺複製或深複製,併為其編寫文件,以告知類的其他使用者。

相關推薦

Object-C定義實現協議

如果嘗試使用自定義類(例如,人類(person類)、地址簿類(myBook類)、分數類(Fraction類))中的copy方法,如 myBook = [myBook mutableCopy]; person = [Person copy];等類似的操作,將會收到一條異

.NET/C#定義物件集合進行定義排序的方法

一個集合可否排序,要看系統知不知道排序的規則,像內建的系統型別,int ,string,short,decimal這些,系統知道怎麼排序,而如果一個集合裡面放置的是自定義型別,比如自己定義了一個Car型別,要把它排序,系統是不知道怎麼辦的。 那麼,如何告知系統排序的規則

C# 使用迭代器實現定義的foreach遍歷

假設我們實現了一個自定義棧, 需要對其從棧頂到棧底遍歷一遍, 找到需要的元素. 我們可以在類內部提供一個迭代器GetEnumerator , 而不必實現整個 IEnumerable介面. 當編譯器檢測到迭代器時, 它將自動生成 IEnumerable 或 I

c#定義泛型、泛型方法和泛型接口

泛型方法 return bsp 其中 tel sts code 方式 void ? 泛型的產生其中一個原因就是為了解決原來集合類中元素的裝箱和拆箱問題: 一、泛型類: /// <summary> /// 返回前臺的消息 /// &

ssm框架通過定義異常實現事務的管理

什麼時候回滾事務? 在spring的事務管理中我們首先要明白這個問題,一般是在丟擲執行期異常的時候會進行事務的回滾。而spring的宣告式事務管理只接受執行期異常。 異常通常分為執行期異常和編譯期異常。 在java中常見的執行期異常有: NullPointerExcept

vector存放定義 ,的要求

vector中存放自定義類的前提是: 自定義的類必須有預設建構函式。因為vector會呼叫預設建構函式來初始化元素的物件。 那必須要明確:編譯器什麼時候隱式宣告預設建構函式? 有兩個條件: · 該類沒有顯式宣告任何建構函式。--既然你都定義了,系統就不給你生成了。 · 資料

Idea_學習_03_IDEA使定義型的文件進行代碼高亮識別

segment tar register 定義 類型 自定義類 pos edi ref 如果你只是想用xml的編輯模式來編輯*.screen文件的話,可以在 Settings->Editor->File Types 中,在Recognized File Ty

Java定義和ArrayList<E>的使用案例

自定義類和ArrayList的使用 自定義類: 將生活中事物抽象成程式碼,或者說是對生活中事物的一種對映。 1.類是一種引用資料型別 2.類中包含了屬性和功能, 屬性:事物的特性,例如:name(姓名),gender(性別),color(顏色),brand(品牌),siz

Objective-C學習筆記-定義

1.OC中一個類由.h檔案和.m檔案組成,.h檔案負責宣告介面,.m檔案負責具體實現 2.在.h檔案中@interface後面的格式為類名:基類名 3.成員變數需要寫在大括號內,最好使用下劃線開頭,使用成員變數需要寫存取方法,為了開發效率,目前推薦使用屬性代替成員變數,屬

C#定義控制元件的屬性、事件及一些相關特性的總結

今天學習了下C#使用者控制元件開發新增自定義屬性的事件,主要參考了MSDN,總結並實驗了一些用於開發自定義屬性和事件的特性(Attribute)。 在這裡先說一下我的環境: 作業系統:Windows7旗艦版(Service Pack 1) VS版本:Microsoft

【術】c#字典Dictionary定義作為key鍵

最近事情有點多,總是想直接貼程式碼,先放上去再說吧。 using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Xml; usin

map使用定義指標作為key

//先上程式碼 #pragma once //想用類作為key,必須過載<運算子 或者提供 //想用指標作為key,也是可以的,不過要自己提供仿函式 class CBase { public:     explicit CBase(int a);     ~CBase(void); private:

定義,實現ArrayList基本功能

import java.util.Arrays; import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.NoSuchEleme

Android使用定義View實現shape圖形繪製

概述 之前曾寫過一篇文章介紹了Android中drawable使用Shape資源,通過定義drawable中的shape資源能夠繪製簡單的圖形效果,如矩形,橢圓形,線形和圓環等。後來我在專案中正好遇到這樣一個需求,要在特定的位置上顯示一條垂直的虛線。正當我胸有

問題解決——在STL的queue使用定義

本文原創,轉載請保證文章的完整性,並顯要的註明出處。 平時很少用STL,就算用,也基本是使用queue<int>之類的簡單資料型別,偶爾在MFC裡寫點小程式碼,用的也是queue<CString>。 (求不要吐槽我為什麼用CString不用stri

淺談VB6定義的使用

   PS:除非特別宣告,本文所說VB指的是VB6,而非VB.NET。    大家都知道,VB是一種半面向物件(也有人稱之為“偽面向物件”)的語言,他雖然可以寫自定義的類,但是由於種種原因,使得他在這方面的發育產生了一點問題,比如說:VB寫出來的類是不能繼承的(不孕不育?!-_-#...傳說VB的偶像是東方

HashMap使用定義作為Key時,為何要重寫HashCode和Equals方法

ide string https object 避免 equals方法 args sys 添加 之前一直不是很理解為什麽要重寫HashCode和Equals方法,才只能作為鍵值存儲在HashMap中。通過下文,可以一探究竟。 首先,如果我們直接用以下的Person類

C#定義操作主窗體控制元件,通過委託實現

主窗體中包含一個標籤label1和一個按鈕button1 程式碼如下: public void ChangeLabel(string text) { label1.Text = text; } private void button1_Click(o

C# 有關控件、定義事件的委托鏈的獲取、移除操作

ons class 單擊 spa inf += finish ati pre 直接來代碼吧,這樣幹脆直接,也不耽誤我午休了。一切盡在源碼中。 public class ControlEventTool { /// <summary>

SpringMVC的異常處理(全域性異常處理定義異常進行統一處理)

前言: WEB開發中,總會有一些不可預料的錯誤,對於一些課預測的異常,我們可以自定義一個異常類,然後再載入個全域性異常處理器,對系統中出現的異常進行統一的處理。 注意:當你在Springmvc配置檔案中配置全域性異常處理器的時候,只要如下配置即可: <!