2016-08-10 2 views
1

Ich habe ein Problem, ich kann nicht ändern frame.size.width in 3rd Party lib. Konnte keine normale Lösung finden, um die Breite zu ändern, also entschied ich mich, objc/Laufzeit auszuführen.Objective-C Laufzeit ändern schreibgeschützte Eigenschaft des initialisierten Objekts

Ich habe ViewController und seine Eigenschaft 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 bekam @property (.., nur lesbar) DTAttributedTextContentView * attributedTextContentView

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

     UIEdgeInsets _edgeInsets; 

     NSMutableDictionary *customViewsForAttachmentsIndex; 

     BOOL _flexibleHeight; 

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

attributedTextContentView bekam @property DTCoreTextLayoutFrame * layoutFrame

@interface DTCoreTextLayoutFrame : NSObject 
{ 
    CGRect _frame; 

    NSArray *_lines; 
    NSArray *_paragraphRanges; 

    NSArray *_textAttachments; 
    NSAttributedString *_attributedStringFragment; 
} 

Also im Grunde muss ich Änderung

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

für eine pitty i cant

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

, weil ich nicht ivars durch Punktnotation noch

, zugreifen noch CGStruct als CGFloat erforderlich Ereignis, wenn & senden.

Als eine andere Lösung für diese Situation sehe ich Erstellen von Objekt für Objekt mit Laufzeit und dann den Zeiger ändern. Vielleicht könnten einige Schritte mit Kopieren gemacht werden. Mein Problem ist, dass ich total neu in objc/Runtime und auch Dokumentation ist wirklich schlecht. Ich kämpfe, um diese bedeutende Technologie zu lernen, also bin ich absichtlich nicht das genaue Problem, das andere Wahlen benutzt.

Jede Hilfe würde sehr geschätzt werden. Vielen Dank im Voraus.

+0

BTW Ich löste das ursprüngliche Problem mit Rahmen, mit Standart Objekt Erstellung. Die Verwendung der Laufzeit für die dynamische Wertänderung ist jedoch immer noch aktuell. – KysokZla

Antwort

0

Es scheint, dass Sie irgendwas falsch machen, aber wenn Sie wirklich eine andere Instanz Ivar müssen eingestellten Wert (dies zu unvorhersehbaren Verhalten führen könnte), ist es das, was Sie wissen müssen:

1) zugeordnete Objekt kein Teil der Instanz ist, wenn Sie also Objekt mit Schlüsseln, dass gleiche Eigenschaft/ivar Namen ändern, es wird nicht den Wert der Eigenschaft/ivar

2) Sie cannot change the part of structure dieses Strukturobjekt eine Eigenschaft von

wenn es im Zusammenhang stehen ist

3) Sie können auf Ivars zugreifen, indem Sie valueForKey:/aufrufenWenn accessInstanceVariablesDirectly Eigenschaft nicht überschrieben wird.

4) Sie müssen wrap your structure to NSValue vor setValue:forKey:

zu vorbei So sollte das Ergebnis Code wie folgt aussehen:

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

Weitere Informationen über KVC, Key-Value Coding Programming Guide überprüfen.

Update:

Wenn Sie Runtime-Funktionen verwenden möchten, müssen Sie:

1) erhalten Offset von Instanzvariablen (alle Objective-C-Objekte sind Strukturen)

2) Erstelle einen Zeiger auf den interessierenden iVar

3) Lese/schreibe direkt von diesem Zeiger

Das ist der 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; 
+0

Yeap, danke, ich löste es mit der gleichen Ansatz - alle Objekte nacheinander, aber meine Frage ist noch aktuell, wie dieses Problem mit Laufzeitfunktionen zu lösen. – KysokZla

+0

Eigentlich erstelle ich keine Objekte (außer NSValue - CGRect Wrapper) in Lösung. Aber ich habe Ansatz hinzugefügt, der Laufzeitfunktionen verwendet. –

Verwandte Themen