[英]Global default value for Objective-C block
我有一個需要一個塊的初始化程序。 我還想要一個不需要該塊的便利初始化程序,而是使用該塊的全局默認實例:
ABCDef.m
:
#import "ABCDefaultReader.h"
@implementation ABCDef {
NSString *(^_reader)(NSString *name);
}
- (instancetype)initWithReader:(NSString *(^)(NSString *name))reader {
self = [super init];
if (self) {
_reader = reader;
}
return self;
}
- (instancetype)init {
// ABCDefaultReader imported from ABCDefaultReader.h
return [self initWithReader:ABCDefaultReader];
}
ABCDefaultReader.h
:
extern NSString *(^ABCDefaultReader)(NSString *name);
ABCDefaultReader.m
:
#import "ABCDefaultReader.h"
extern NSString *(^ABCDefaultReader)(NSString *name) = ^NSString *(NSString *name) {
// ...
}
這無法構建,因為'extern' variable has an initializer
(我正在使用-Werror
):
ABCDefaultReader.m:3:36: error: 'extern' variable has an initializer [-Werror,-Wextern-initializer]
extern NSString *(^ABCDefaultReader)(NSString *name) = ^NSString *(NSString *name) {
^
1 error generated.
在 Objective-C(或更准確地說,在 C 中)中,當您有這樣的全局時,
實際的全局變量應該在源文件中( .m
Objective-C 文件,或.c
在 C 的情況下)。 在這里你可以包括初始化。 但不應使用extern
限定符。
.h
應該有extern
聲明(沒有初始化)以將此全局公開給其他編譯單元。
讓我們考慮一個更簡單的示例(將 Objective-C 塊的句法噪聲排除在等式之外)。
因此,我們在.m
文件中聲明一個全局...
// Foo.m
#import "Foo.h"
NSInteger baz = 42;
@implementation Foo
@end
...我們在其.h
header 中公開該全局:
// Foo.h
#import <Foundation/Foundation.h>
extern NSInteger baz;
@interface Foo : NSObject
@end
現在我們可以從其他文件訪問該全局:
// Bar.m
#import "Bar.h"
#import "Foo.h"
@implementation Bar
- (void)qux {
NSLog(@"%ld", (long)baz); // 42
}
@end
您問:
- 為什么有一個初始化器是個問題?
extern
實際上意味着“在其他地方有一個全局實現”。 在那里初始化它沒有意義。
- 在單獨的文件中定義默認的常量塊並從我的實現 class 中引用的好方法是什么?
雖然您可以使用上面概述的正確extern
模式,但我建議您完全不要使用全局變量。 我可能有這個塊的class
屬性。 或者我可能有這個塊的實例屬性,然后把它放在某個共享實例中(一個你在需要的地方注入的共享實例,或者在非常狹窄的情況下,可能是一個單例)。 如果沒有更多上下文,很難在您的特定情況下說。
但我們通常會避免污染全局命名空間。
順便說一句,您已將此塊描述為“常量”。 如果您的意思不是真的“恆定”,那么請忽略以下內容,但如果是這樣,請繼續閱讀:
當您定義了這個全局時,它是可變的並且可以被代碼中的任何地方替換。 如果它真的是一個常數,你應該包括const
限定符:
// .h
extern NSString *(^const ABCDefaultReader)(NSString *);
// .m
extern NSString *(^const ABCDefaultReader)(NSString *) = ^(NSString *string) {
// do something with `string`
NSString *result = ...
return result;
}
當然,這引出了一個問題,即如果塊是常量,為什么還要使用它。 塊的價值是調用者可以提供一個代碼塊,被調用的例程將利用它。 例如,如果我們想調用一些 Objective-C 方法,我們可能只創建一個 class 方法:
// Foo.h
@interface Foo: NSObject
+ (NSString *)bar:(NSString *)input;
@end
和
// Foo.m
@implementation Foo
+ (NSString *)bar:(NSString *)input {
NSString *output = ...
return output;
}
@end
然后你會這樣稱呼它:
// Baz.m
@implementation Baz
- (void)someRoutine {
NSString *result = [Foo bar:@"baz"];
// do something with `result`
}
@end
這是一個可以在任何地方調用的例程,無需使用全局變量,不需要實例化有問題的 object,但該方法的命名空間很好。
刪除 .m 文件中的extern
。 “extern”的意思是“這是在其他地方定義的”,但你在這里定義它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.