2011-02-16 74 views
2

我有一個自定義類Custom.mm,我試圖在我的控制器類MainController中使用setter設置浮動值。 Custom實例被鍵入爲一個id,因爲它是一個Obj-C++文件,並且在編譯時指向一個合適的類對我來說工作得很好。一切正常,實例已驗證。如果我將int變量設置爲int類型,並通過ints,則它可以正常工作。與任何其他值或對象相同 - 除了浮動。由於某些原因,Float(float,CGFloat等)在Custom.mm類中被設置爲0。這不是NSLog或其他任何問題 - 我已經用斷點檢查了數量變量,並且所有東西都可以正常工作,但卻是浮動的。CGFloats,浮動設置爲零

//Custom.h 
@interface Custom : UIView 
{ 

     CGFloat amount; 

} 

@property CGFloat amount; 

@end 

//Custom.mm 
@implementation Custom 
@synthesize amount; 

- (id) initWithCoder:(NSCoder*)coder 
{ 
    if ((self = [super initWithCoder:coder])) 
    { 
     //set initial value to 1 
     self.amount = 1.0; //verified as 1.0 
    } 
    return self; 
} 

//MainController.h 
@interface MainController : UIViewController 
{ 
    IBOutlet id customInstance; //IB points to the CustomView class 
} 

//MainController.m 
@implementation MainController 

-(void)viewDidLoad 
{ 
     [super viewDidLoad]; 

     //Checking this value in Custom.mm via the debugger shows it as being 0, 
     //when before it was 1.0. 
     [customInstance setAmount:2.0]; 
    } 

@end 
+3

你能分享失敗的實際源代碼嗎?當正確執行金額= 1行時,您如何「在Custom.mm中檢查此值」? – drewh 2011-02-16 01:19:35

+1

使用點符號時會發生同樣的事情:`customInstance.amount = 2.0`? – 2011-02-16 01:39:15

+0

@drewh amount = 1在初始化時被設置。我使用調試器以及日誌記錄來檢查這些值。 – akaru 2011-02-16 05:03:04

回答

6

我能夠重現這個我自己;你遇到了一個有趣的現象。

您的問題是編譯器無法看到setAmount:方法的定義。因此,它不知道該方法所期望的參數的正確類型。在這種情況下,編譯器假定所有參數的類型都是'...',而返回值的類型是'id'。但是你傳遞的是CGFloat,而不是'...'。

Objective-C是一種動態語言,因此即使編譯器不知道目標方法是否存在,它也會樂於打包參數並嘗試調用它。 但是,在大多數體系結構中,傳遞參數的方法取決於參數的類型。整數和指針參數通常在一組寄存器中傳遞,而浮點參數在另一組寄存器中傳遞,而結構體通常直接在堆棧上傳遞。 (精確的細節取決於你正在運行的體系結構。)由於編譯器無法看到setAmount:方法的定義,因此它假定參數的類型爲...。根據體系結構的不同,這些寄存器可以被傳遞到不同的寄存器組中,甚至可以在堆棧中傳遞。

然而,當setAmount:方法運行時,它期望傳入的參數位於某組寄存器中。那些呼叫者當然沒有填充,因此仍然被設置爲0.呼叫者將新值放在一個位置,但接收者在另一個位置查看。難怪事情出錯了。

解決方案很簡單:在MainController.m的頂部添加#import "Custom.h"然後,編譯器在編譯MainController時將能夠看到setAmount:的定義,並因此知道將新值置於接收器期望的位置。順便說一句,我敢打賭,當你編譯時,你會得到一個警告;像

warning: no '-setAmount:' method found 
warning: (Messages without a matching method signature 
warning: will be assumed to return 'id' and accept 
warning: '...' as arguments.) 

至少,這是我得到的警告。那是編譯器告訴你,在進行這個調用時它不知道把參數放在哪裏,所以它只是選擇了一些東西,並希望它能夠工作。在這種情況下,它沒有。

至於int和其他類型的正確工作,編譯器對參數傳遞樣式的猜測恰好與接收者期望的匹配。這只是一個簡單的運氣問題。

0

它看起來像你沒有指定一個自定義對象到MainController的customInstance變量,所以它是零。詢問零的任何東西,它會給你0.