OC面試題1

im5437發表於2015-05-19

Object-C有多繼承嗎?沒有的話用什麼代替?

cocoa 中所有的類都是NSObject 的子類
多繼承在這裡是用protocol 委託代理 來實現的
你不用去考慮繁瑣的多繼承 ,虛基類的概念.
ood
的多型特性  obj-c 中通過委託來實現.


Object-C
有私有方法嗎?私有變數呢?

objective-c– 類裡面的方法只有兩種靜態方法和例項方法這似乎就不是完整的物件導向了,按照OO的原則就是一個物件只暴露有用的東西如果沒有了私有方法的話對於一些小範圍的程式碼重用就不那麼順手了在類裡面聲名一個私有方法
@interface Controller : NSObject { NSString *something; }
+ (void)thisIsAStaticMethod;
– (void)thisIsAnInstanceMethod;
@end
@interface Controller (private) -
(void)thisIsAPrivateMethod;
@end

@private可以用來修飾私有變數
ObjectiveC中,所有例項變數預設都是私有的,所有例項方法預設都是公有的

關鍵字const什麼含義

const意味著只讀,下面的宣告都是什麼意思?
const int a;
int const a;
const int *a;
int * const a;
int const * a const;

前兩個的作用是一樣,a是一個常整型數。第三個意味著a是一個指向常整型數的指標(也就是,整型數是不可修改的,但指標可以)。第四個意思a是一個指向整型數的常指標(也就是說,指標指向的整型數是可以修改的,但指標是不可修改的)。最後一個意味著a是一個指向常整型數的常指標(也就是說,指標指向的整型數是不可修改的,同時指標也是不可修改的)。

結論:
•; 
關鍵字const的作用是為給讀你程式碼的人傳達非常有用的資訊,實際上,宣告一個引數為常量是為了告訴了使用者這個引數的應用目的。如果
你曾花很多時間清理其它人留下的垃圾,你就會很快學會感謝這點多餘的資訊。(當然,懂得用const的程式設計師很少會留下的垃圾讓別人來清
理的。)
•; 
通過給優化器一些附加的資訊,使用關鍵字const也許能產生更緊湊的程式碼。
•; 
合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的引數,防止其被無意的程式碼修改。簡而言之,這樣可以減少bug的出現。

欲阻止一個變數被改變,可以使用 const 關鍵字。在定義該 const 變數時,通常需要對它進行初
始化,因為以後就沒有機會再去改變它了;
2)對指標來說,可以指定指標本身為 const,也可以指定指標所指的資料為 const,或二者同時指
定為 const
3)在一個函式宣告中,const 可以修飾形參,表明它是一個輸入引數,在函式內部不能改變其值;
4)對於類的成員函式,若指定其為 const 型別,則表明其是一個常函式,不能修改類的成員變數;
5)對於類的成員函式,有時候必須指定其返回值為 const 型別,以使得其返回值不為左值

關鍵字volatile有什麼含義?並給出三個不同例子?

一個定義為volatile的變數是說這變數可能會被意想不到地改變,這樣,編譯器就不會去假設這個變數的值了。精確地說就是,優化器在用到
這個變數時必須每次都小心地重新讀取這個變數的值,而不是使用儲存在暫存器裡的備份。下面是volatile變數的幾個例子:
• 
並行裝置的硬體暫存器(如:狀態暫存器)
• 
一箇中斷服務子程式中會訪問到的非自動變數(Non-automatic variables)
• 
多執行緒應用中被幾個任務共享的變數

• 一個引數既可以是const還可以是volatile嗎?解釋為什麼。
• 
一個指標可以是volatile 嗎?解釋為什麼。

下面是答案:
• 
是的。一個例子是隻讀的狀態暫存器。它是volatile因為它可能被意想不到地改變。它是const因為程式不應該試圖去修改它。
• 
是的。儘管這並不很常見。一個例子是當一箇中服務子程式修該一個指向一個buffer的指標時。

static作用?

函式體內 static 變數的作用範圍為該函式體,不同於 auto 變數,該變數的記憶體只被分配一次,
因此其值在下次呼叫時仍維持上次的值;
2)在模組內的 static 全域性變數可以被模組內所用函式訪問,但不能被模組外其它函式訪問;
3)在模組內的 static 函式只可被這一模組內的其它函式呼叫,這個函式的使用範圍被限制在宣告
它的模組內;
4)在類中的 static 成員變數屬於整個類所擁有,對類的所有物件只有一份拷貝;
5)在類中的 static 成員函式屬於整個類所擁有,這個函式不接收 this 指標,因而只能訪問類的static 成員變數。

#import#include的區別,@class代表什麼?

@class一般用於標頭檔案中需要宣告該類的某個例項變數的時候用到,在m檔案中還是需要使用#import
#import比起#include的好處就是不會引起重複包含

執行緒和程式的區別?

程式和執行緒都是由作業系統所體會的程式執行的基本單元,系統利用該基本單元實現系統對應用的併發性。
程式和執行緒的主要差別在於它們是不同的作業系統資源管理方式。程式有獨立的地址空間,一個程式崩潰後,在保護模式下不會對其它程式產生影響,而執行緒只是一個程式中的不同執行路徑。執行緒有自己的堆疊和區域性變數,但執行緒之間沒有單獨的地址空間,一個執行緒死掉就等於整個程式死掉,所以多程式的程式要比多執行緒的程式健壯,但在程式切換時,耗費資源較大,效率要差一些。但對於一些要求同時進行並且又要共享某些變數的併發操作,只能用執行緒,不能用程式。

堆和棧的區別?

管理方式:對於棧來講,是由編譯器自動管理,無需我們手工控制;對於堆來說,釋放工作由程式設計師控制,容易產生memory leak
申請大小:
棧:在Windows,棧是向低地址擴充套件的資料結構,是一塊連續的記憶體的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。
堆:堆是向高地址擴充套件的資料結構,是不連續的記憶體區域。這是由於系統是用連結串列來儲存的空閒記憶體地址的,自然是不連續的,而連結串列的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬記憶體。由此可見,堆獲得的空間比較靈活,也比較大。
碎片問題:對於堆來講,頻繁的new/delete勢必會造成記憶體空間的不連續,從而造成大量的碎片,使程式效率降低。對於棧來講,則不會存在這個問題,因為棧是先進後出的佇列,他們是如此的一一對應,以至於永遠都不可能有一個記憶體塊從棧中間彈出
分配方式:堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如區域性變數的分配。動態分配由alloca函式進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由編譯器進行釋放,無需我們手工實現。
分配效率:棧是機器系統提供的資料結構,計算機會在底層對棧提供支援:分配專門的暫存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是C/C++函式庫提供的,它的機制是很複雜的。

Object-C的記憶體管理?

1.當你使用new,alloccopy方法建立一個物件時,該物件的保留計數器值為1.當你不再使用該物件時,你要負責向該物件傳送一條releaseautorelease訊息.這樣,該物件將在使用壽命結束時被銷燬.
2.
當你通過任何其他方法獲得一個物件時,則假設該物件的保留計數器值為1,而且已經被設定為自動釋放,你不需要執行任何操作來確保該物件被清理.如果你打算在一段時間內擁有該物件,則需要保留它並確保在操作完成時釋放它.
3.
如果你保留了某個物件,你需要(最終)釋放或自動釋放該物件.必須保持retain方法和release方法的使用次數相等.

為什麼很多內建的類,如TableViewControllerdelegate的屬性是assign不是retain

迴圈引用
所有的引用計數系統,都存在迴圈應用的問題。例如下面的引用關係:
    •    
物件a建立並引用到了物件b.
    •    
物件b建立並引用到了物件c.
    •    
物件c建立並引用到了物件b.
這時候bc的引用計數分別是21。當a不再使用b,呼叫release釋放對b的所有權,因為c還引用了b,所以b的引用計數為1b不會被釋放。b不釋放,c的引用計數就是1c也不會被釋放。從此,bc永遠留在記憶體中。
這種情況,必須打斷迴圈引用,通過其他規則來維護引用關係。比如,我們常見的delegate往往是assign方式的屬性而不是retain方式的屬性,賦值不會增加引用計數,就是為了防止delegation兩端產生不必要的迴圈引用。如果一個UITableViewController 物件a通過retain獲取了UITableView物件b的所有權,這個UITableView物件bdelegate又是a 如果這個delegateretain方式的,那基本上就沒有機會釋放這兩個物件了。自己在設計使用delegate模式時,也要注意這點。

定義屬性時,什麼情況使用copyassignretain

assign用於簡單資料型別,如NSInteger,double,bool,
retain
copy用於物件,
copy
用於當a指向一個物件,b也想指向同樣的物件的時候,如果用assigna如果釋放,再呼叫bcrash,如果用copy 的方式,ab各自有自己的記憶體,就可以解決這個問題。
retain 
會使計數器加一,也可以解決assign的問題。
另外:atomicnonatomic用來決定編譯器生成的gettersetter是否為原子操作。在多執行緒環境下,原子操作是必要的,否則有可能引起錯誤的結果。
加了atomicsetter函式會變成下面這樣:
if (property != newValue) {
[property release];
property = [newValue retain];
}

物件是什麼時候被release的?

引用計數為0時。
autorelease
實際上只是把對release的呼叫延遲了,對於每一個Autorelease,系統只是把該Object放入了當前的Autorelease pool中,當該pool被釋放時,該pool中的所有Object會被呼叫Release。對於每一個Runloop 系統會隱式建立一個Autoreleasepool,這樣所有的releasepool會構成一個象CallStack一樣的一個棧式結構,在每一個Runloop結束時,當前棧頂的Autorelease pool會被銷燬,這樣這個pool裡的每個Object(就是autorelease的物件)會被release。那什麼是一個Runloop呢? 一個UI事件,Timer call delegate call 都會是一個新的Runloop

iOS有沒有垃圾回收?

Objective-C 2.0也是有垃圾回收機制的,但是隻能在Mac OS X Leopard 10.5 以上的版本使用。

tableView的重用機制?

 檢視UITableView標頭檔案,會找到NSMutableArray*  visiableCells,和NSMutableDictnery* reusableTableCells兩個結構。visiableCells內儲存當前顯示的cellsreusableTableCells儲存可重用的cells

  TableView顯示之初,reusableTableCells為空,那麼tableViewdequeueReusableCellWithIdentifier:CellIdentifier返回nil。開始的cell都是通過[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]來建立,而且cellForRowAtIndexPath只是呼叫最大顯示cell數的次數。

  比如:有100條資料,iPhone一屏最多顯示10cell。程式最開始顯示TableView的情況是:

  1. [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]建立10cell,並給cell指定同樣的重用標識(當然,可以為不同顯示型別的cell指定不同的標識)。並且10cell全部都加入到visiableCells陣列,reusableTableCells為空。

  2. 向下拖動tableView,當cell1完全移出螢幕,並且cell11(它也是alloc出來的,原因同上)完全顯示出來的時候。cell11加入到visiableCellscell1移出visiableCellscell1加入到reusableTableCells

3. 接著向下拖動tableView,因為reusableTableCells中已經有值,所以,當需要顯示新的cellcellForRowAtIndexPath再次被呼叫的時候,tableView dequeueReusableCellWithIdentifier:CellIdentifier,返回cell1cell1加入到visiableCellscell1移出reusableTableCellscell2移出visiableCellscell2加入到reusableTableCells。之後再需要顯示的Cell就可以正常重用了。


ViewController 
loadViewviewDidLoadviewDidUnload分別是什麼時候呼叫的,在自定義ViewCointroller時在這幾個函式中應該做什麼工作?

initloadViewviewDidLoadviewDidUnloaddealloc的關係說起
init
方法
init方法中例項化必要的物件(遵從LazyLoad思想)
init
方法中初始化ViewController本身

loadView方法
view需要被展示而它卻是nil時,viewController會呼叫該方法。不要直接呼叫該方法。
如果手工維護views,必須過載重寫該方法
如果使用IB維護views,必須不能過載重寫該方法

loadViewIB構建view
你在控制器中實現了loadView方法,那麼你可能會在應用執行的某個時候被記憶體管理控制呼叫。 如果裝置記憶體不足的時候, view 控制器會收到didReceiveMemoryWarning的訊息。 預設的實現是檢查當前控制器的view是否在使用。 如果它的view不在當前正在使用的view hierarchy裡面,且你的控制器實現了loadView方法,那麼這個view將被release, loadView方法將被再次呼叫來建立一個新的view

viewDidLoad方法
viewDidLoad 
此方法只有當viewnib檔案初始化的時候才被呼叫。
過載重寫該方法以進一步定製view
iPhone OS3.0及之後的版本中,還應該過載重寫viewDidUnload來釋放對view的任何索引
viewDidLoad
後呼叫資料Model

viewDidUnload方法
當系統記憶體吃緊的時候會呼叫該方法(注:viewController沒有被dealloc
記憶體吃緊時,在iPhone OS3.0之前didReceiveMemoryWarning是釋放無用記憶體的唯一方式,但是OS 3.0及以後viewDidUnload方法是更好的方式
在該方法中將所有IBOutlet(無論是property還是例項變數)置為nil(系統release view時已經將其release掉了)

在該方法中釋放其他與view有關的物件、其他在執行時建立(但非系統必須)的物件、在viewDidLoad中被建立的物件、快取資料等release物件後,將物件置為nilIBOutlet只需要將其置為nil,系統release view時已經將其release掉了)

一般認為viewDidUnloadviewDidLoad的映象,因為當view被重新請求時,viewDidLoad還會重新被執行

viewDidUnload中被release的物件必須是很容易被重新建立的物件(比如在viewDidLoad或其他方法中建立的物件),不要release使用者資料或其他很難被重新建立的物件

dealloc方法
viewDidUnload
dealloc方法沒有關聯,dealloc還是繼續做它該做的事情


ViewController
didReceiveMemoryWarning是在什麼時候呼叫的?預設的操作是什麼?

當程式接到記憶體警告時View Controller將會收到這個訊息:didReceiveMemoryWarning

iOS3.0開始,不需要過載這個函式,把釋放記憶體的程式碼放到viewDidUnload中去。

這個函式的預設實現是:檢查controller是否可以安全地釋放它的view(這裡加粗的view指的是controllerview屬性),比如view本身沒有superview並且可以被很容易地重建(從nib或者loadView函式)。

如果view可以被釋放,那麼這個函式釋放view並呼叫viewDidUnload

你可以過載這個函式來釋放controller中使用的其他記憶體。但要記得呼叫這個函式的super實現來允許父類(一般是UIVIewController)釋放view

如果你的ViewController儲存著view的子view的引用,那麼,在早期的iOS版本中,你應該在這個函式中來釋放這些引用。而在iOS3.0或更高版本中,你應該在viewDidUnload中釋放這些引用。

 

列舉Cocoa中常見的集中多執行緒的實現,並談談多執行緒安全的幾種解決辦法,一般什麼地方會用到多執行緒?

NSOperationNSThread
@sychonized

怎麼理解MVC,在CocoaMVC是怎麼實現的?

MVC設計模式考慮三種物件:模型物件、檢視物件、和控制器物件。模型物件代表特別的知識和專業技能,它們負責保有應用程式的資料和定義運算元據的邏輯。檢視物件知道如何顯示應用程式的模型資料,而且可能允許使用者對其進行編輯。控制器物件是應用程式的檢視物件和模型物件之間的協調者。
ViewCotroller
Xib

delegatenotification區別,分別在什麼情況下使用?

KVC(Key-Value-Coding)
KVO
Key-Value-Observing
理解KVCKVO(鍵--編碼與鍵--監看)

當通過KVC呼叫物件時,比如:[self valueForKey:@”someKey”]時,程式會自動試圖通過幾種不同的方式解析這個呼叫。首先查詢物件是否帶有 someKey 這個方法,如果沒找到,會繼續查詢物件是否帶有someKey這個例項變數(iVar),如果還沒有找到,程式會繼續試圖呼叫 -(id) valueForUndefinedKey:這個方法。如果這個方法還是沒有被實現的話,程式會丟擲一個NSUndefinedKeyException異常錯誤。

(Key-Value Coding查詢方法的時候,不僅僅會查詢someKey這個方法,還會查詢getsomeKey這個方法,前面加一個get,或者_someKey以及_getsomeKey這幾種形式。同時,查詢例項變數的時候也會不僅僅查詢someKey這個變數,也會查詢_someKey這個變數是否存在。)

設計valueForUndefinedKey:方法的主要目的是當你使用-(id)valueForKey方法從物件中請求值時,物件能夠在錯誤發生前,有最後的機會響應這個請求。


self.
self什麼區別?


id
nil代表什麼?

id

 

idvoid *並非完全一樣。在上面的程式碼中,id是指向struct objc_object的一個指標,這個意思基本上是說,id是一個指向任何一個繼承了Object(或者NSObject)類的物件。需要注意的是id是一個指標,所以你在使用id的時候不需要加星號。比如id foo=nil定義了一個nil指標,這個指標指向NSObject的一個任意子類。而id *foo=nil則定義了一個指標,這個指標指向另一個指標,被指向的這個指標指向NSObject的一個子類。

 

nil

 

nilC語言的NULL相同,在objc/objc.h中定義。nil表示一個Objctive-C物件,這個物件的指標指向空(沒有東西就是空)。

記憶體管理 Autoreleaseretaincopyassignset方法和含義?

1,你初始化(alloc/init)的物件,你需要釋放(release)它。例如:

  NSMutableArray aArray = [[NSArray alloc] init];

  後,需要

  [aArray release];

  2,你retaincopy的,你需要釋放它。例如:

  [aArray retain]

  後,需要

  [aArray release];

  3,被傳遞(assign)的物件,你需要斟酌的retainrelease。例如:

  obj2 = [[obj1 someMethod] autorelease];

  物件2接收物件1的一個自動釋放的值,或傳遞一個基本資料型別(NSIntegerNSString)時: 你或希望將物件2進行retain,以防止它在被使用之前就被自動釋放掉。但是在retain後,一定要在適當的時候進行釋放。

 

  關於索引計數(Reference Counting)的問題

  retain = 索引計數(ReferenceCounting)

  NSArray物件會retain(retain值加一)任何陣列中的物件。當NSArray被解除安裝(dealloc)的時候,所有陣列中的物件會被執行一次釋放(retain值減一)。不僅僅是NSArray,任何收集類(CollectionClasses)都執行類似操作。例如NSDictionary,甚至UINavigationController

  Alloc/init建立的物件,索引計數為1。無需將其再次retain

  [NSArray array][NSDate date]方法建立一個索引計數為1的物件,但是也是一個自動釋放物件。所以是本地臨時物件,那麼無所謂了。如果是打算在全Class中使用的變數(iVar),則必須retain它。

  預設的類方法返回值都被執行了自動釋放方法。(*如上中的NSArray)

  在類中的解除安裝方法“dealloc”中,release所有未被平衡的NS物件。(*所有未被autorelease,而retain值為1)

類別的作用?

有時我們需要在一個已經定義好的類中增加一些方法,而不想去重寫該類。比如,當工程已經很大,程式碼量比較多,或者類中已經包住很多方法,已經有其他程式碼呼叫了該類建立物件並使用該類的方法時,可以使用類別對該類擴充新的方法。

  注意:類別只能擴充方法,而不能擴充成員變數。

委託(舉例)

委託代理(degegate),顧名思義,把某個物件要做的事情委託給別的物件去做。那麼別的物件就是這個物件的代理,代替它來打理要做的事。反映到程式中,首先要明確一個物件的委託方是哪個物件,委託所做的內容是什麼。
委託機制是一種設計模式,在很多語言中都用到的,這只是個通用的思想,網上會有很多關於這方面的介紹。
那麼在蘋果開發過程中,用到委託的程式實現思想如下,我主要拿如何在檢視之間傳輸資訊做個例子。
譬如:在兩個頁面(UIIview檢視物件)實現傳值,用委託(delegate)可以很好做到!
方法:
A
@interface A
UIView
        id transparendValueDelegate;
       @property(nomatic, retain) idtransparendValueDelegate;
@end

@implemtion A
@synthesize transparendValueDelegate
-(void)Function

      NSString* value = @"hello";
      //
讓代理物件執行transparendValue動作
      [transparendValueDelegate transparendValue:value];
}
@end

B
@interface B
UIView
      NSString* value;
@end

@implemtion B
-(void)transparendValue:(NSString*)fromValue
{
      value = fromValue;
      NSLog(@"the value is %@",value); 
}
@end

//
下面的設定A代理委託物件為B
//
在定義AB類物件處:

A* a = [[A alloc] init];
B* b = [[B alloc] init];
a. transparendValueDelegate = b;//
設定物件a代理為物件b

這樣在檢視AB之間可以通過委託來傳值!

下面這個例子委託有兩類:
1
、一個檢視類物件的代理物件為父檢視,子檢視用代理實現讓父檢視顯示別的子檢視
2
、同一父檢視下的一個子檢視為另一個子檢視的代理物件,讓另一個子檢視改變自身背景色為給定的顏色
===============================================
規範格式如下:
@protocol TransparendValueDelegate;

@interface A
UIView
id< TransparendValueDelegate > m_dTransparendValueDelegate;
@property(nomatic, retain) id m_dTransparendValueDelegate;
@end
//
代理協議的宣告
@protocol TransparendValueDelegat<NSObject>
{
      -(void)transparendValue:(NSString*)fromValue;
}

retainCount



1.objective-c中的數字物件都有哪些,簡述它們與基本資料型別的區別是什麼
2.用NSLog函式輸出一個浮點型別,結果四捨五入,並保留一位小數
3.擷取字串”20|http://www.621life.com“ 中 ‘|’字元前面及後面的資料,分別輸出它們
4.objective-c中的詞典物件、可變詞典物件是哪個,初始化一個含有兩個鍵值對的可變詞典物件,並動態的新增和刪除一條記錄,輸出第一條記錄
5.獲取專案根路徑,並在其下建立一個名稱為userData的目錄。
6.在一個物件的方法裡面:self.name = “object”;和name =”object”有什麼不同嗎?
7.定義屬性時,什麼情況使用copy,assign,和retain

第3題:
NSRange range = [responseString rangeOfString:@"|"];
int location = range.location;
NSString *str1 = [responseString substringToIndex:location];
NSString *str2 = [responseString substringFromIndex:location+1];
第4題:
NSDictionary NSMutableDictionary
NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"value1",@"key1",@"value2",@"key2",nil];
[dic setObject:@"value3" forKey:@"key3"];
[dic removeObjectForKey:@"key3"];
[dic objectForKey:@"key1"];
第5題:
// 獲取根路徑
NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:];
// 建立檔案系統管理器
NSFileManager *fileManager = [[NSFileManager alloc] init];
// 判斷userData目錄是否存在
if(![fileManager fileExistsAtPath:[NSString stringWithFormat:@"%@/userData", documentsDirectory]]) {
// 不存在,建立一個userData目錄
[fileManager createDirectoryAtPath:[NSString stringWithFormat:@"%@/userData", documentsDirectory]withIntermediateDirectories:false attributes:nil error:nil];
}
第6題:
self.name = “object”會呼叫物件的setName()方法,
name = “object”會直接把object賦值給當前物件的name 屬性。
並且 self.name 這樣retainCount會加1,而name就不會。

第 7題:
assign用於簡單資料型別,如NSInteger,double,bool,retain 和copy使用者物件,copy用於當 a指向一個物件,b也想指向同樣的物件的時候,如果用assign,a如果釋放,再呼叫b會crash,如果用copy 的方式,a和b各自有自己的記憶體,就可以解決這個問題。retain 會使計數器加一,也可以解決assign的問題。另外:tomic和nonatomic用來決定編譯器生成的getter和setter是否為原子操作。在多執行緒環境下,原子操作是必要的,否則有可能引起錯誤的結果。

相關文章