【问题标题】:Assigned to Readonly Property Objective-C分配给只读属性 Objective-C
【发布时间】:2015-08-07 06:37:12
【问题描述】:

我正在编写一个单元测试来测试一个更新清单的方法。清单具有以下属性:

typedef NS_ENUM (NSUInteger, ChecklistStatus) { Pending, Completed };
@protocol IChecklistItem <NSObject>
@property (nonatomic, assign, readonly) NSInteger Id;
@property (nonatomic, copy, readonly) NSString *Description;
@property (nonatomic, assign, readonly)BOOL IsCompleted;
@property (nonatomic, assign, readwrite) ChecklistStatus Status;
@property (nonatomic, strong, readwrite) NSDate *CompletedDate;
@property (nonatomic, copy, readwrite) NSString *CompletedByUserId;
@property (nonatomic, assign, readonly) NSInteger RoleId;
@property (nonatomic, assign, readonly) NSInteger GroupId;
@property (nonatomic, strong, readonly) NSArray<IChecklistNote> *Notes;

- (void)sortNotes;
@end

但是,在我的单元测试中,当我试图验证时,

checklistItem.Description = @"hello";,我收到错误“Assignment to readonly property”

为什么会这样?

这是我的测试方法的其余部分:

- (void)testUpdateChecklist {
    NSString *testChecklistId = @"1";
    NSString *testPatientDescription = @"Descriptive Description";

    // What other properties do I need here?
    XCTAssertNotNil(_service);
    __block CCChecklistItem *checklistItem = nil;

    SignalBlocker *blocker = [[SignalBlocker alloc] initWithExpectedSignalCount:1];
    id delegate = OCMProtocolMock(@protocol(ChecklistServiceDelegate));
    OCMExpect([delegate didCompleteUpdateChecklistItem:[OCMArg checkWithBlock:^BOOL(id obj) {
        checklistItem = obj;
        XCTAssertNotNil(checklistItem);
        [blocker signal];
        return true;
    }]]);

    [_service updateChecklistItem:checklistItem delegate:delegate];
    [blocker waitWithTimeout:5.0f];
    OCMVerifyAll(delegate);

    NSString *originalDescription = checklistItem.Description;

    checklistItem.Description = @"hello";

}

编辑问题:

所以当我将属性从上面更改为 ReadWrite 时,我在 CChecklistItem 中收到此错误

@interface CCChecklistItem ()
@property (nonatomic, assign, readwrite) NSInteger Id;
@property (nonatomic, copy, readwrite) NSString *Description;
@property (nonatomic, assign, readwrite) NSInteger RoleId;
@property (nonatomic, assign, readwrite) NSInteger GroupId;
@property (nonatomic, strong, readwrite) NSMutableArray<IChecklistNote> *Notes;
@end

`类扩展'CChecklistItem'中读写属性的非法重新声明

【问题讨论】:

  • 你明白readonly属性属性是什么意思吗?
  • 1.不要写默认参数,因为那是过时的代码 == 更难阅读(例如readwrite,可能都是assignstrong)。 2. 在 obj-c 中,我们使用小写首字母命名变量。 3.正如其他答案中所指出的,您可以删除readonly 标志:如果您测试此变量的设置,它应该是readwrite。如果它应该是readonly,你不应该尝试在你的测试中设置它。

标签: objective-c


【解决方案1】:

您的属性设置为readonly,如下所示:

@property (nonatomic, copy, readonly) NSString *Description;

改成:

@property (nonatomic, copy) NSString *Description;

或者如果您想与其他属性保持一致(尽管过于明确,IMO):

@property (nonatomic, copy, readwrite) NSString *Description;

【讨论】:

  • 谢谢..我不敢相信我没有看到...你碰巧知道如何引用类型枚举吗?我想引用它,就像你对字符串所做的那样,NSString *string = @"hello",但是对于 Enums
  • 那就是 TypeName variableName = &lt;number&gt;;,其中 TypeName 是 typedef NS_ENUM(NSInteger, TypeName) {...};,并确保在引用 variableName 时省略 *
  • 你在两个不同的地方声明了这个属性。 @protocol IChecklistItem@interface CCChecklistItem ()。选一个应该没问题的。错误消息几乎解释了发生了什么。
  • @VarunVarahabotla 希望这有助于解决您的问题。如果是这样,如果您能批准答案,我将不胜感激!谢谢。
【解决方案2】:

不鼓励仅为了满足测试而更改范围可见性。在您的情况下,最简单的解决方案是利用 Objective-C 为您提供的美妙的 KVO

翻译成你原来的问题是这样的:

[checklistItem setValue:@"hello" forKey:@"Description"]

无需更改访问修饰符,您的测试就可以了。

【讨论】:

    【解决方案3】:

    您的属性在类CChecklistItem 符合的协议中声明为readonly。然后合成该属性时,它将创建支持变量和一个getter方法-(NSString *)description;,但没有setter方法,因为它是readonly。因此,在您的匿名类别中将其重新声明为 readwright,我猜是在您的测试文件中声明以将私有方法公开给测试用例,因为仍然没有该属性的 setter 方法,所以它不起作用。此外,即使您决定尝试在类上的类别实现中创建自己的 setter,您也无法访问,因为无法访问仅在 CChecklistItem.m 文件中公开的变量 _description

    根据您需要对测试执行的操作,它可能适用于 stub 吸气剂 - (NSString *)description; 并在调用该方法时返回您的 @"hello" 字符串,而不是尝试将实际值设置为支持变量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-27
      • 2011-06-02
      • 2019-05-08
      • 1970-01-01
      • 2019-12-06
      相关资源
      最近更新 更多