OC @property与块类别

时间:2018-03-23 16:36:36

标签: objective-c properties objective-c-blocks objective-c-runtime objective-c-category

对不起我想在类别中使用block作为我的属性来改变我的代码风格,如下所示,但是有些错误,我不知道为什么。
这是我的代码:
```

typedef NSString* (^MethodreplacingRangeWithString)(NSRange range,NSString * string);
typedef NSString* (^MethodAppend)(NSString *) ;
@interface NSString (Speech)
@property(nonatomic ,copy)MethodreplacingRangeWithString replacingRangeWithString ;
@property(nonatomic, copy)MethodAppend append ;
+(void)speech:(NSString *)content;
@end

@implementation NSString (Speech)

//setter and getter
static NSString * a = @"replacingRangeWithString" ;
-(void)setReplacingRangeWithString:(MethodreplacingRangeWithString)replacingRangeWithString{
    objc_setAssociatedObject(self, @selector(replacingRangeWithString), replacingRangeWithString, OBJC_ASSOCIATION_RETAIN_NONATOMIC) ;
}
-(MethodreplacingRangeWithString)replacingRangeWithString{
    return objc_getAssociatedObject(self, @selector(replacingRangeWithString)) ;
}

//setter and getter
static NSString * b = @"append" ;
-(void)setAppend:(MethodAppend)append{
    objc_setAssociatedObject(self, @selector(append), append,OBJC_ASSOCIATION_RETAIN_NONATOMIC) ;
}
-(MethodAppend)append{
    return objc_getAssociatedObject(self, @selector(append)) ;
}
//block
-(void)configureReplacingRangeWithStringProperty{
    __weak typeof (self) weakSelf = self ;
    self.replacingRangeWithString =  ^(NSRange range,NSString * str){
        return [weakSelf stringByReplacingCharactersInRange:range withString:str];
    };
}
-(void)configureAppend{
    __weak typeof (self)weakSelf = self ;
    self.append = ^(NSString *str){
        return [weakSelf stringByAppendingString:str] ;
    };
}

to change the style as follows :

NSString * str = @"hello world" ;
        [str configureAppend] ;
        [str configureReplacingRangeWithStringProperty] ;
        str = str.replacingRangeWithString(NSMakeRange(6, 5),@"iOS").append(@" hhhhh") ;

```

这是我的配置错误,我不知道为什么

2 个答案:

答案 0 :(得分:0)

您将属性声明为copy,然后实施strong setter。

更有可能的是,崩溃是因为在堆栈帧被销毁后,堆栈上有一个块正在被使用。

答案 1 :(得分:0)

您遇到的实际崩溃的原因可能是由于对相关对象的误解。将对象关联到特定实例时,而不是关联到同一类型的所有实例。

查看您的代码:

[str configureAppend] ;
[str configureReplacingRangeWithStringProperty] ;

此时,您已将两个对象与str所指的特定实例相关联。现在你尝试做:

str = str.replacingRangeWithString(NSMakeRange(6, 5),@"iOS").append(@" hhhhh") ;

打破这个局面:

str.replacingRangeWithString

这会在任何引用的对象实例replacingRangeWithString上调用属性str。让我们调用该对象A.现在你的前两个语句将对象与A相关联,因此这样可以恢复你的块引用。

str.replacingRangeWithString(NSMakeRange(6, 5),@"iOS")

这将调用块并返回不同的字符串,并调用该对象B.

str.replacingRangeWithString(NSMakeRange(6, 5),@"iOS").append

这会调用对象B上的属性append,您没有与对象B关联的对象,因此返回空引用。

str.replacingRangeWithString(NSMakeRange(6, 5),@"iOS").append(@" ahhhh")

你试图调用你的“阻止”,但你有一个空引用=>记忆错误。

<强>更新

此时我原本建议您需要重新考虑您的设计 - 您这样做 - 而且解决方案可能并不像您想的那么简单 - 从那时起,我就明白可能有一个简单的方法......

已提供您只是尝试使用属性访问替换方法调用,以便您可以将调用整齐地链接在一起;即您无意使用执行不同操作的块调用configure...方法;然后您可以在您的属性中动态创建并返回一个块。以下是append的大纲。首先使该属性为只读:

@property(nonatomic, readonly) MethodAppend append;

然后使用:

定义它
-(MethodAppend)append
{
   NSString *copied = self.copy;
   return ^(NSString *string){ return [copied stringByAppendingString:string]; };
}

这首先复制字符串以防它被调用的实例是NSMutableString,你不知道在调用这个属性多长时间后将调用该块并且字符串值可能已被更改到那时。然后它返回一个接受所需参数的块并调用预期的方法。

这就是所需要的,没有setter或configure方法,也没有关联对象。

HTH