OC @属性 块在类别中

OC @property with block in category

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

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") ;

```

我的配置有问题,我不知道为什么

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

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

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

查看您的代码:

[str configureAppend] ;
[str configureReplacingRangeWithStringProperty] ;

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

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

分解:

str.replacingRangeWithString

这会在 str 引用的任何对象实例上调用 属性 replacingRangeWithString。我们称该对象为 A。现在您之前的两个语句将对象与 A 相关联,所以这有效并且您可以取回块引用。

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

这会调用块和 return 一个 不同的 字符串,将该对象称为 B。

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

这会在对象 B 上调用 属性 append,您没有将任何对象与对象 B 相关联,因此这 return 是一个空引用。

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

您试图调用您的 "block",但您有一个空引用 => 内存错误。

更新

在这一点上,我最初建议你需要重新考虑你的设计 - 你确实这样做了 - 并且解决方案可能不像你想要的那么简单 - 从那时起我就意识到可能有一个简单的方法...

提供 你只是想用 属性 访问替换方法调用,这样你就可以整齐地将调用链接在一起;也就是说,您无意使用执行不同操作的块调用 configure... 方法;那么您可以在 属性 中动态创建和 return 一个块。这是 append 的大纲。首先将 属性 设为只读:

@property(nonatomic, readonly) MethodAppend append;

然后使用以下方式定义它:

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

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

这就是所有需要的,没有设置器或配置方法,也没有关联对象。

HTH