【问题标题】:Class issues: should I use everywhere self as class in objective c?班级问题:我应该在目标 c 中到处使用 self 作为班级吗?
【发布时间】:2014-05-05 10:16:24
【问题描述】:

哇,我自己发现了一个好问题。

这是什么?糖果还是大蒜?

关于 Objective-C 的一些事情:

在 (+) - 类方法中不使用“self”作为类有什么问题吗?

在一堂课的深处……

+(NSDate*)dateWithTimeInterval:(NSTimeInterval)interval {
    return [self dateWithTimeIntervalSince1970:interval];
}

这里是鲁比: 例如,在 Ruby 中,一切都是对象,类是类的对象,并且有一个依赖自我的好习惯:

class DateClass 
     # self is DateClass here, inside of class definition, uh
     self.dateWithTimeInterval(interval)
         self.dateWithTimeIntervalSince1970(interval)
     end
end

这里是 Perl: 另一个例子是在perl oop deep中找到的:(感谢this thread

sub new {
    my $proto = shift || die "Must pass a class or object into new()";
    my $class = ref($proto) || $proto;
    bless {}, $class;
}

所以,在 Perl 和 Ruby 中,人们总是依赖 $class refs

也许 Perl 代码的例子并不明显,但它总是会发生。程序员依赖 $class 引用并使用它的类名。此外,他们可以使用它调用一些方法:

 my $class = 'Class';
    $class->new();

    Class::->new()

毕竟...

对于在 Objective-c 中使用 self 作为类,您可以提供哪些陷阱或警告?

【问题讨论】:

  • 你是在问[self dateWithTimeIntervalSince1970:interval]; VS 的优缺点吗? [NSDate dateWithTimeIntervalSince1970:interval]; ?
  • @Visput,是的,关于它

标签: objective-c


【解决方案1】:

通常,您可以尽可能使用self,但当然,在某些情况下需要通过[MyClass class] 引用类。几乎所有的场景都与继承有关。

例如,类A.的创建者方法

@implementation A

+ (id)createInstanceWithParam:(NSInteger)param {
   return [[self alloc] initWithParam:param];
}

@end

即使我们创建子类B 也能正常工作。但是,如果我们决定实现一个类集群,那么我们必须通过名称来引用类:

@implementation SomeDataStructure

+ (id)createInstanceWithType:(NSInteger)type {
    if (type == 0) {
       return [[DataStructureImpl1 alloc] init];
    }
    else if (type == 1) {
       return [[DataStructureImpl2 alloc] init];
    }
}

@end

另一个例子是+initialize的常见例子

+ (void)initialize {
    if (self == [MyClass class]) {
        ...perform initialization...
    }
}

当然,如果您要重写一个方法,那么使用self 或使用[MySelf class] 可以区分您的重写实现和原始实现。虽然super 也可以在那里使用。

TLDR: self 是首选,但要小心子类/超类。

【讨论】:

  • 感谢您提供的示例。但是为什么你使用== 的平等呢?进行班级比较是否安全?
  • 绝对安全,initialize 示例直接来自 Apple 文档。元类永远只有一个实例。
【解决方案2】:

为了了解使用selfclass name 的优缺点,让我们考虑一种情况:
ANSDate 的子类并实现方法+(NSDate*)dateWithTimeInterval:(NSTimeInterval)interval

B 类是A 的子类,并覆盖在NSDate 中声明的+dateWithTimeIntervalSince1970:(NSTimeInterval)interval 方法的实现。

现在让我们考虑A+(NSDate*)dateWithTimeInterval:(NSTimeInterval)interval 方法的两种可能实现:

1.使用self

+(NSDate*)dateWithTimeInterval:(NSTimeInterval)interval {
    return [self dateWithTimeIntervalSince1970:interval];
}

如果在上面的代码中运行[B dateWithTimeInterval:interval];,那么self 是一种B 类,并且正如预期的那样,+(NSDate*)dateWithTimeIntervalSince1970:(NSTimeInterval)interval 方法的自定义实现(在B 类中)将被调用。

2.直接使用NSDate

+(NSDate*)dateWithTimeInterval:(NSTimeInterval)interval {
    return [NSDate dateWithTimeIntervalSince1970:interval];
}

如果运行[B dateWithTimeInterval:interval];,那么重写的实现(在B 类中)将被忽略,取而代之的是:+(NSDate*)dateWithTimeIntervalSince1970:(NSTimeInterval)interval 方法的原始实现(在NSDate 类中)将被调用。之所以如此,是因为我们直接向NSDate[NSDate dateWithTimeIntervalSince1970:interval];发送消息。
这种行为对于开发人员来说是意外的。

出于同样的原因,以这种方式声明方法:

+(instancetype)dateWithTimeInterval:(NSTimeInterval)interval {
    return [self dateWithTimeIntervalSince1970:interval];
}

通过使用instancetype,编译器将知道方法初始化器返回什么样的对象。当您调用 [B dateWithTimeInterval:interval] 时,它返回类型为 B 的对象,但不返回 NSDate

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-26
    • 2017-10-23
    • 1970-01-01
    • 2018-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多