亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》
  • 首頁 > 
  • 教程 > 
  • 開發技術 > 
  • objc方法怎么聲明和實現由于參數類型不一致所引發的崩潰

objc方法怎么聲明和實現由于參數類型不一致所引發的崩潰

發布時間:2023-03-31 15:43:58 來源:億速云 閱讀:94 作者:iii 欄目:開發技術

本篇內容主要講解“objc方法怎么聲明和實現由于參數類型不一致所引發的崩潰”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“objc方法怎么聲明和實現由于參數類型不一致所引發的崩潰”吧!

正文

你有注意過objc方法聲明處和方法實現處參數類型不一致的情況嗎,就像這樣:

@interface Person : NSObject
- (void)frothTime:(NSInteger)regionTime value1:(BOOL)value;
@end
@implementation Person
- (void)frothTime:(NSInteger)regionTime value1:(NSString *)value;
@end

這2個方法除了第2個參數的類型不一樣,其它都一樣,但一旦調用這個方法就會產生一個壞內存訪問的崩潰,這是為什么呢?

這是我在真實項目中遇到的1個很有意思的問題,只要調用分類中的某個方法就百分百崩潰,而且控制臺沒有任何有用的報錯信息,被調用的方法里面的代碼也都沒有執行,非常難調試,我花了一些時間才弄懂了其中的原理,整理后分享出來,希望能幫到你,崩潰如下圖所示:

objc方法怎么聲明和實現由于參數類型不一致所引發的崩潰

以下是我簡寫后的代碼,它是一份完整的代碼并且可以直接運行。

@interface Person : NSObject
- (void)frothTime:(NSInteger)regionTime value1:(BOOL)value;
@end
@interface Person (Category)
- (void)frothTime:(NSInteger)regionTime;
- (void)frothTime:(NSInteger)regionTime value1:(NSString *)value;
@end
@implementation Person
- (void)frothTime:(NSInteger)regionTime value1:(BOOL)value {
    NSLog(@"%s", __func__);
}
@end
@implementation Person (Category)
- (void)frothTime:(NSInteger)regionTime {
    [self frothTime:regionTime value1:@"111"];
}
- (void)frothTime:(NSInteger)regionTime value1:(NSString *)value {
    NSLog(@"%s", __func__);
}
@end
int main(int argc, const char * argv[]) {
    Person *p = [[Person alloc] init];
    [p frothTime:123];
    return 0;
}

分析

運行代碼后,會在 - (void)frothTime:(NSInteger)regionTime value1:(NSString *)value 這行代碼處產生一條 EXC_BAD_ACCESS 崩潰問題,通過打印和斷點,可以看出方法內的代碼并沒有執行,說明是調用這個方法時發生的崩潰,所以可以排除是方法內的代碼問題。

崩潰前的代碼位置是 [self frothTime:regionTime value1:@"111"];,這行代碼從表面上看沒有任何問題,如果你把示例代碼粘貼到 xcode 中,編譯器可能會在這行代碼后面給出1個警告: "Incompatible pointer to integer conversion sending 'NSString *' to parameter of type 'BOOL' (aka 'signed char')",意思是說方法接收的是一個 BOOL 類型的參數,而你傳了一個 NSString * 類型。

仔細看一下代碼,你會發現 Person 類中聲明了 - (void)frothTime:(NSInteger)regionTime value1:(BOOL)value;,而且分類中也有一個類似的聲明 - (void)frothTime:(NSInteger)regionTime value1:(NSString *)value;,它們除了第2個參數類型不一樣,其它都是一樣的;熟悉objc的同學應該都知道,objc是沒有方法重載的概念,也就是說分類中的方法其實和類中的方法,它們的方法簽名都是 frothTime:value1:

現在有2個同名的方法實現,那么 [self frothTime:regionTime value1:@"111"]; 到底調用哪個方法呢?按照 xcode 給出的提示,似乎是調用 - (void)frothTime:(NSInteger)regionTime value1:(BOOL)value; 這個方法,因為編譯器提示第2個參數類型不一致。

有些同學在這里或許有一個疑問,明明有2個方法,而且分類中的方法明顯更適合調用方,為什么編譯器認為我們調用的是類中的方法而不是分類中的方法;有2點原因,第1是因為objc沒有方法重載的概念,所以這2個方法對編譯器來說其實都是一樣的;第2是因為objc的分類是運行時加載的,編譯器在編譯時并不知道分類以及分類方法的存在。

和其它語言不一樣,objc的方法聲明和實現可以重復,只是不能在一個作用域中重復,例如在 @interface 和 @end 就不能同時存在 - (void)frothTime:(NSInteger)regionTime value1:(BOOL)value;- (void)frothTime:(NSInteger)regionTime value1:(NSString *)value;,即使它們的參數類型并不是完全一樣;但是可以在分類中寫出和類中一樣的方法聲明或實現,即使你在分類中寫出 - (void)frothTime:(NSInteger)regionTime value1:(BOOL)value; 這種和類中的方法完全一模一樣的方法也不會有任何報錯信息,如果你不小心在分類中實現了和類中同名的方法,那么運行時會永遠調用分類中的方法實現,不清楚為什么的同學自行上網尋找答案。

現在我們弄明白了為什么編譯器會給出警告,也知道了實際調用的其實是分類中的方法實現,但分類中的方法參數類型和我們傳遞的參數類型明明是一致的,那為什么還會崩潰呢?

原因在于編譯器在對代碼進行編譯時對 @"111" 這個參數是按照 BOOL 類型而不是 NSString 類型處理的,請看下圖:

objc方法怎么聲明和實現由于參數類型不一致所引發的崩潰

使用 xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc 文件路徑 -o 輸出的文件路徑.cpp 將objc代碼編譯為C++代碼。

可以看到編譯器把參數強轉成了 bool 類型,但是方法實現處卻是按照 NSString 類型進行接收的,按照 NSString 類型去訪問一個 bool 類型的內存,這就是崩潰的真正原因

補充

如果你嘗試將 - (void)frothTime:(NSInteger)regionTime value1:(BOOL)value; 修改為 - (void)frothTime:(NSInteger)regionTime value1:(NSObject *)value;(其實可以把value的參數類型修改為任意objc對象類型,只要不是基礎數據類型就行),注意:這里我只修改了方法聲明處的參數類型,并沒有修改方法實現處的參數類型;然后運行項目;正常運行并輸出;編譯后的代碼截圖如下:

objc方法怎么聲明和實現由于參數類型不一致所引發的崩潰

從截圖中可以看到參數雖然還是被強轉成了 NSObjet 類型,但是據我觀察,只要是objc對象都沒關系,你可以把它改為 NSArray 等任何 objc 對象類型,雖然有編譯警告,但是并不影響運行。

另外,你也可以將 [self frothTime:regionTime value1:@"111"]; 修改為 [self performSelector:@selector(frothTime:value1:) withObject:@(regionTime) withObject:@"111"];,項目也可以正常運行,原因和上面一樣,因為 withObject 的參數類型是 id。

到此,相信大家對“objc方法怎么聲明和實現由于參數類型不一致所引發的崩潰”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

邹平县| 丹棱县| 宁陕县| 镇赉县| 定南县| 中西区| 澄江县| 徐汇区| 开远市| 新平| 龙陵县| 交城县| 会东县| 古浪县| 遂昌县| 余干县| 凤冈县| 简阳市| 皮山县| 晋州市| 平谷区| 高碑店市| 山阴县| 汉沽区| 昌宁县| 淳化县| 丽江市| 谢通门县| 前郭尔| 南雄市| 南平市| 崇文区| 金堂县| 莱阳市| 格尔木市| 黑水县| 安丘市| 景谷| 珠海市| 洛浦县| 如东县|