Objective-C运行时更改初始化对象的只读属性

时间:2016-08-10 12:40:53

标签: ios objective-c runtime objective-c-runtime

我遇到了问题,我无法更改第三方库中的frame.size.width。找不到任何改变宽度的正常解决方案,所以我决定执行 objc / runtime

我有ViewController及其属性 DTAttributedTextView * v。

@interface DTAttributedTextView : UIScrollView
{
 // ivars needed by subclasses
 DTAttributedTextContentView *_attributedTextContentView;
}

 @property (nonatomic, strong) NSAttributedString *attributedString;
 @property (nonatomic, DT_WEAK_PROPERTY) IBOutlet 
 id<DTAttributedTextContentViewDelegate> textDelegate;
 @property (nonatomic, strong) IBOutlet UIView *backgroundView;
 ....
@end

v得到@property(..,readonly) DTAttributedTextContentView * attributedTextContentView

 @interface DTAttributedTextContentView : UIView
 {
      NSAttributedString *_attributedString;
      DTCoreTextLayoutFrame *_layoutFrame;

      UIEdgeInsets _edgeInsets;

      NSMutableDictionary *customViewsForAttachmentsIndex;

      BOOL _flexibleHeight;

      // for layoutFrame
      NSInteger _numberOfLines;
      NSLineBreakMode _lineBreakMode;
      NSAttributedString *_truncationString;
}

attributedTextContentView得到@property DTCoreTextLayoutFrame * layoutFrame

 @interface DTCoreTextLayoutFrame : NSObject 
 {
   CGRect _frame;

   NSArray *_lines;
   NSArray *_paragraphRanges;

   NSArray *_textAttachments;
   NSAttributedString *_attributedStringFragment;
 }

所以基本上我需要改变

self.v.attributedTextContentView.layoutFrame.frame.size.width

因为我不能使用

objc_setAssociatedObject(self.v.attributedTextContentView.layoutFrame,@"frame.size.width",@200,OBJC_ASSOCIATION_ASSIGN);

,也不

objc_setAssociatedObject(self.v.attributedTextContentView.layoutFrame,@"frame",CGRectMake(0,0,200,1000),OBJC_ASSOCIATION_ASSIGN);

因为我不能通过点表示法访问ivars,也不能发送CGStruct作为CGFloat所需的事件,如果&amp;。

作为这种情况的另一种解决方案,我看到使用运行时按对象创建对象,然后更改指针。也许可以使用副本完成一些步骤。 我的问题是,我在objc / runtime和文档中的新手总是很差。我努力学习这项重要的技术,所以我故意不使用其他选项解决确切的问题。

任何帮助都将受到高度赞赏。 提前完成。

1 个答案:

答案 0 :(得分:0)

看起来你做错了事,但如果你真的需要将值设置为另一个实例ivar(这可能导致不可预测的行为),这就是你需要知道的:

1)关联对象不是实例的一部分,因此如果使用等于property / ivar name的键添加关联对象,则不会更改property / ivar的值

2)你cannot change the part of structure如果这个结构是对象的属性

3)如果accessInstanceVariablesDirectly属性未被覆盖,您可以致电valueForKey: / setValue:forKey:来访问ivars。

4)在转到setValue:forKey:

之前,您需要wrap your structure to NSValue

因此,结果代码应如下所示:

DTCoreTextLayoutFrame *layoutFrame = self.v.attributedTextContentView.layoutFrame;
CGRect frame = [[layoutFrame valueForKey:@"_frame"] CGRectValue];
frame.size.width = 200.0;
NSValue* frameValue = [NSValue valueWithCGRect:frame];
[layoutFrame setValue:frameValue forKey:@"_frame"];

有关KVC的更多信息,请查看Key-Value Coding Programming Guide

<强>更新

如果要使用运行时功能,则需要:

1)获取实例变量的偏移量(所有objective-c对象都是结构)

2)创建指向您感兴趣的ivar的指针

3)直接读/写这个指针

这是代码:

DTCoreTextLayoutFrame *layoutFrame = self.v.attributedTextContentView.layoutFrame;    
Ivar ivar = class_getInstanceVariable([DTCoreTextLayoutFrame class], "_frame");
ptrdiff_t offset = ivar_getOffset(ivar);
CGRect *framePtr = (__bridge void*)layoutFrame + offset;
CGRect frame = *framePtr;
frame.size.width = 100;
*framePtr = frame;