Это все из-за принципа замены Лискова
Согласно этому принципу:
, если S является подтипом T,тогда объекты типа T могут быть заменены объектами типа S. без изменения каких-либо желательных свойств программы.
В вашем примере: Bar
является подтипом Foo
.Таким образом, вы должны иметь возможность заменить экземпляр Foo
на экземпляр Bar
.
Другими словами, представьте метод
- (void)doSomethingWith:(Foo *)object {
[object m:nil];
}
Если вы передадите этому методу экземпляр Foo
- все отлично.Но вы не можете передать ему экземпляр Bar
- потому что вы не можете вызвать [Bar m:nil]
Здесь вы можете видеть, что этот код нарушает принцип подстановки Лискова.
В противном случае во втором примере все в порядке.
Представьте себе метод:
- (void)doSomethingWith:(Foo *)object {
[object m:@""]; // _Nonnull requirement
}
Как видите, вы можете перейти к экземплярам этого методаклассов Foo
и Bar
.
ПРИМЕЧАНИЕ: Здесь важно отметить, что в Objc (в отличие от Swift) эти правила не так строги, и вы можетелегко обмануть компилятор.