我原来是一名Java程序员,现在使用Objective-C.我想创建一个抽象类,但在Objective-C中似乎不可能.这可能吗?
如果没有,我可以在Objective-C中获得一个抽象类的接近程度?
在设计类层次结构时,有时子类添加了一个新initWithSomeNewParam方法,并且希望禁用对init从超类继承的旧方法的调用.
首先,我在这里阅读了这个问题,其中提出的替代方法是覆盖init在运行时抛出异常,或覆盖并设置属性的默认值.在我的情况下,我不想提供默认值,我想清楚地表明不应该调用旧方法,而应该使用带参数的新方法.
因此运行时异常很好,但除非代码被调试,否则团队中的其他程序员无法注意到旧方法不再用于使用.
如果我是正确的,那么就没有办法将方法标记为"私有".所以,除了添加评论之外,有没有办法做到这一点?
提前致谢.
我的问题如下:我有一个单例类型的对象(我正在使用ARC),在实现文件中有这个代码
+(id)sharedInstance
{
static DataManager *sharedInstance;
if (sharedInstance == nil) {
sharedInstance = [[DataManager alloc] init];
}
return sharedInstance;
}
+(NSManagedObjectContext *)getManagedContext
{
AppDelegate *applicationDelegate =(AppDelegate *)[[UIApplication sharedApplication] delegate];
return [applicationDelegate managedObjectContext];
}
+(void)saveContext:(NSManagedObjectContext *)context
{
NSError *error;
if (![context save:&error]) {
NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
}
}
#pragma mark - Data management methods
+(void)addPersonWithName:(NSString *)name andPicture:(UIImage *)picture
{
NSManagedObjectContext *context = [self getManagedContext]; //no problem here
//some code
[self saveContex:context]; // no known class method for selector …Run Code Online (Sandbox Code Playgroud) 我有两个班,一个接一个的子类(比如Animal和Dog).超类有一些初始化器(比方说initAnimal),子类有一些初始化器(比方说initDog).问题是完全合法(从编译器的角度来看)做类似的事情Dog *adog = [[Dog alloc] initAnimal],即.使用超类初始化程序初始化类.我不喜欢这个,因为子类可以有一些我想确保初始化的额外实例变量.查看头文件可以解决这个问题,但有一种简单的方法可以让编译器检查一下吗?我有一种感觉,我错过了一些非常明显的东西,但我不能把手指放在它上面:-)
更新:在initDog和initAnimal不是最好的例子.我的意思是两个非常不同的初始化器(比如initfor Animal和initWithFurfor Dog).如果我希望每只狗都分配一些毛皮,我会将毛皮作为初始化器的一部分,这样就没有人可以获得没有皮毛的狗对象了.但是后来用超类错误地初始化实例仍然很容易init,然后我就被软管了.
感谢您提出指定的初始化程序,杰森.之前我没有想过,但我可以重载超类的指定初始化程序并在那里设置一些合理的默认值.但是我仍然更愿意,如果我能以某种方式使用其他初始化程序而不是类本身的那些非法 - 更多的想法?
从Adapting Modern Objective-C文档:
如果类提供一个或多个指定的初始值设定项,则它必须实现其超类的所有指定初始值设定项.
这意味着如果我有一个子类NSObject具有自己的指定初始化器,比如说
- (instancetype)initWithImage:(UIImage*)image NS_DESIGNATED_INITALIZER;
Run Code Online (Sandbox Code Playgroud)
那么我还需要提供NSObjects的实现-init.我应该怎么做才能将-init初始化程序标记为"无效",即没有人应该调用它而是使用它-initWithImage:?这里最好的做法是什么?
我尝试了这里描述的技术.
但是,当我在接口中标记超类-init方法时unavailable,编译器仍然告诉我需要覆盖超类的初始化器.
当我尝试其他技术,即引发异常或调用-doesNotRecognizeSelector:内部时-init,我收到一条错误,指出我需要调用我指定的初始化程序之一.
好吧,这无疑是一个最佳实践问题,但我想要做对,所以希望有人可以启发我:
场景是非常标准的,但有一个转折点:我在我编写的框架中有一个类,它直接继承自NSObject.它有一个指定的初始化程序,有很多参数,其中大部分都是nonnull.由于东西是框架的一部分,我明确地使用NS_DESIGNATED_INITIALIZER宏(我不总是在较小的个人应用程序中做).问题是这导致XCode警告我也覆盖init,即超类的指定初始化程序.但另外它要求我从它调用我指定的initalizer,这是我不能做的,因为我的参数缺乏有意义的默认值.我真的不想在"小"中抛出异常init,我更愿意回归nil.
为了摆脱警告,我init在我班级的扩展中添加了第二个指定的initalizer,如下所示:
@interface MyClassName ()
// some other stuff not relevant`
-(nullable instancetype)init NS_DESIGNATED_INITIALIZER;
@end
Run Code Online (Sandbox Code Playgroud)
现在我可以安全地使用我想要return nil;的覆盖init方法.这意味着我的文档(我正在使用appledoc)和扩展XCode的代码完成不会告诉某人使用我的框架init实际上也是一个指定的初始化程序(因此他们不会意外地使用它),但它仍然存在(在例如,单元测试可以派上用场).
我的问题是:除了实际在生产中使用它的人之外,还有任何危险吗,之后快乐地发送消息给nil而没有意识到?这是少数几个在init中抛出异常的情况之一吗?
如何确保用户不调用init,而客户端应该调用sharedSingleton来获取共享实例.
@synthesize delegate;
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
+ (LoginController *)sharedSingleton
{
static LoginController *sharedSingleton;
@synchronized(self)
{
if (!sharedSingleton)
sharedSingleton = [[LoginController alloc] init];
CdtMiscRegisterConnectionChangeListenerObjc(test_ConnectionChangeListenerCallback);
return sharedSingleton;
}
}
Run Code Online (Sandbox Code Playgroud) 假设您有一个UIView子类.您定义了一个init方法"myInitWithFrame:... andWhatNot:...".你知道你不会使用从UIView的继承init方法永远和您的自定义init方法做了一些重要的习俗正在初始化,这样要强制客户端类从未使用继承initWithFrame方法.
是否可以隐藏从UIView继承的标准initWithFrame方法?
我创建了一个不同的init方法,并希望它是指定的初始化程序而不是标准-init.如何防止客户端代码使用实例化类-init?
例如
/* everyone must call this */
- (id)initWithInfo:(NSDictionary *)info {
self = [super init];
if (self) {
_info = info;
}
return self;
}
/* Don't want anyone to be able to create this using init */
Run Code Online (Sandbox Code Playgroud) objective-c ×10
ios ×2
singleton ×2
cocoa-touch ×1
inheritance ×1
init ×1
initializer ×1
iphone ×1
macos ×1
oop ×1
xcode ×1