简体   繁体   English

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

[英]Objective-C Runtime changing readonly property of initialized object

i have got an issue, i can't change frame.size.width in 3rd party lib. 我有一个问题,我不能改变第三方库中的frame.size.width。 Could not find any normal solution to change the width, so i decided to execute objc/runtime . 找不到任何改变宽度的正常解决方案,所以我决定执行objc / runtime

I've got ViewController and its property DTAttributedTextView *v. 我有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 got @property ( .., readonly) DTAttributedTextContentView *attributedTextContentView 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 got @property DTCoreTextLayoutFrame *layoutFrame attributedTextContentView得到了@property DTCoreTextLayoutFrame * layoutFrame

 @interface DTCoreTextLayoutFrame : NSObject 
 {
   CGRect _frame;

   NSArray *_lines;
   NSArray *_paragraphRanges;

   NSArray *_textAttachments;
   NSAttributedString *_attributedStringFragment;
 }

So basically i need to change 所以基本上我需要改变

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

for a pitty i cant use 因为我不能使用

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

nor 也不

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

because i can't access ivars by dot notation, nor send CGStruct as CGFloat required event if &. 因为我不能通过点符号访问ivars,也不能发送CGStruct作为CGFloat所需的事件,如果&。

As another solution to this situation i see creating object by object using runtime and then change the pointer. 作为这种情况的另一种解决方案,我看到使用运行时按对象创建对象,然后更改指针。 Maybe some steps could be done using copy. 也许可以使用副本完成一些步骤。 My problem is that im total newbie in objc/runtime and also documentation is really poor. 我的问题是,我在objc / runtime和文档中的新手总是很差。 Im struggling to learn this significant technology so i'm intentionally do not solve the exact problem using other options. 我努力学习这项重要的技术,所以我故意不使用其他选项解决确切的问题。

Any help would be highly appreciated. 任何帮助将受到高度赞赏。 Thanx in advance. Thanx提前。

It seems that you are doing somethings wrong, but if you really need to set value to another instance ivar (this could lead to unpredictable behavior), this is what you need to know: 看起来你做错了什么,但如果你真的需要将值设置为另一个实例ivar(这可能导致不可预测的行为),这就是你需要知道的:

1) associated object is not a part of instance, so if you add associated object with key that equal property/ivar name it will not change the value of property/ivar 1)关联对象不是实例的一部分,因此如果使用等于property / ivar name的键添加关联对象,则不会更改property / ivar的值

2) you cannot change the part of structure if it this structure is a property of object 2)如果此结构是对象的属性, 则无法更改结构的部分

3) you can get access to ivars by calling valueForKey: / setValue:forKey: if accessInstanceVariablesDirectly property is not overriden. 3)您可以通过调用valueForKey:来访问ivars valueForKey: / setValue:forKey:如果accessInstanceVariablesDirectly属性未被覆盖。

4) you need to wrap your structure to NSValue before passing to setValue:forKey: 4)在传递给setValue:forKey:之前,你需要将你的结构包装到NSValue setValue:forKey:

So, the result code should look like this: 因此,结果代码应如下所示:

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

For more information about KVC, check Key-Value Coding Programming Guide . 有关KVC的更多信息,请查看键值编码编程指南

Update: 更新:

If you want to use runtime functions, you need to: 如果要使用运行时函数,则需要:

1) get offset of instance variable (all objective-c objects are structures) 1)获取实例变量的偏移量(所有objective-c对象都是结构)

2) create pointer to the ivar that you are interested in 2)创建指向您感兴趣的ivar的指针

3) read from / write to this pointer directly 3)直接读/写此指针

This is the code: 这是代码:

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM