Wiki source for DummyProxy
One problem you face with the current dual thread architecture is the issue where you invoke message 'foo' on the main thread. This creates a NSInvocation instance to execute on the main thread. The main UI Thread receives notification that has to process your request as part of the UI RunLoop processing. However the timing is such that a touch event is pending and will be serviced first! This touch event triggers a call back to the SqueakProxy instance.
But now you have the Squeak VM waiting in the ObjectiveCBridge code for the main thread to complete, but you have the main thread waiting on the SqueakProxy instance lock to complete as it waits for VM which can't run to respond. A classic deadlock situation.
To avoid this here are some code samples which you setup in applicationDidLaunch: as proxy to either a UITextLabel or UISlider.
The thought is you can either set the text or value, and the proxy looks after sending the data to UITextLabel to UISlider if it exists.
Exists? Yes a problem is that when a memorywarning message is sent to a UIViewController it can dispose of all the UIViews. So
in viewDidLoad: you basically ask the proxy for the data to use for initializing your UITextLabel. Technically you would have to ask
the Squeak VM for the data, but having it shared in the proxy makes this task much easier. But you then must remember to only
get/put data via the proxy, versus tampering with the data in the actual UITextLabel.
Usage:
A DummyClassForTextData may point to
text an NSString* for the UILabel text
placeHolder an NSString* for the UILabel placeHolder
cell the UIView object
DummyClassForUISlider may point to
sliderValue the slider value
cell the UIView object
The methods
setNeedsDisplay to send the setNeedsDisplay message to cell on the main thread no wait.
setTextAndPassThru:setNeedsDisplay: to set the text for the text property and pass that data to the cell.text, also the optional send of setNeedsDisplay
setPlaceHolderAndPassThru:setNeedsDisplay: to set the text for the placeHolder property, on the main thread, no wait.
getText to get the text
text
placeHolder
For the slider you have
setNeedsDisplay to send the setNeedsDisplay message to cell on the main thread no wait.
setValue:animated:setNeedsDisplay: to set the value and do the optional setNeedsDisplay logic on the main thread, no wait.
sliderValue to get the slider value
In future I'll provide a solution to allow you to get the slider value and text/placeHolder data from the cell object on the background
thread. This requires a bit more work since we need to use a Smalltalk external semaphore to make the VM wait until the NSInvocation populates
the instance's property variable.
%%(language-ref)
//
// DummyClassForUIView.h
// WikiWikiServer
//
// Created by John M McIntosh on 14/09/09.
// Copyright 2009 Corporate Smalltalk Consulting Ltd. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface DummyClassForUIView : NSObject {
NSObject *cell;
}
- (void)setNeedsDisplay;
- (void) setNeedsDisplay: (BOOL) display;
@property (nonatomic,assign) NSObject *cell;
@end
//
// DummyClassForUIView.m
// WikiWikiServer
//
// Created by John M McIntosh on 14/09/09.
// Copyright 2009 Corporate Smalltalk Consulting Ltd. All rights reserved.
//
#import "DummyClassForUIView.h"
@implementation DummyClassForUIView
@synthesize cell;
- (void)setNeedsDisplay {
[self setNeedsDisplay: YES];
}
- (void)setNeedsDisplay: (BOOL) display {
if (!self.cell) return;
if (!display) return;
if ([NSThread isMainThread])
[(UIView *) self.cell setNeedsDisplay];
else
[self.cell performSelectorOnMainThread: @selector(setNeedsDisplay) withObject: nil waitUntilDone: NO];
}
@end
//
// DummyClassForTextData.h
// WikiWikiServer
//
// Created by John M McIntosh on 10/09/09.
// Copyright 2009 Corporate Smalltalk Consulting Ltd. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "DummyClassForUIView.h"
@interface DummyClassForTextData : DummyClassForUIView {
NSString *text;
NSString *placeholder;
}
- (NSString *) getText;
- (void) setTextAndPassThru: (NSString *) aString setNeedsDisplay: (BOOL) display;
- (void) setPlaceHolderAndPassThru: (NSString *) aString setNeedsDisplay: (BOOL) display;
@property (nonatomic,retain) NSString *text;
@property (nonatomic,retain) NSString *placeholder;
@end
//
// DummyClassForTextData.m
// WikiWikiServer
//
// Created by John M McIntosh on 10/09/09.
// Copyright 2009 Corporate Smalltalk Consulting Ltd. All rights reserved.
//
#import "DummyClassForTextData.h"
@implementation DummyClassForTextData
@synthesize text,placeholder;
- (void) setPlaceHolderAndPassThru: (NSString *) aString setNeedsDisplay: (BOOL) display {
self.placeholder = aString;
if (self.cell) {
if ([NSThread isMainThread]) {
((UITextField *)self.cell).placeholder = aString;
} else {
[self.cell performSelectorOnMainThread: @selector(setPlaceholder:) withObject: aString waitUntilDone: NO];
}
[self setNeedsDisplay: display];
}
}
- (void) setTextAndPassThru: (NSString *) aString setNeedsDisplay: (BOOL) display {
self.text = aString;
if (self.cell) {
if ([NSThread isMainThread]) {
((UITextField *)self.cell).text = aString;
} else {
[self.cell performSelectorOnMainThread: @selector(setText:) withObject: aString waitUntilDone: NO];
}
[self setNeedsDisplay: display];
}
}
- (NSString *) getText {
return self.text;
}
@end
//
// DummyClassForUISlider.h
// WikiWikiServer
//
// Created by John M McIntosh on 10/09/09.
// Copyright 2009 Corporate Smalltalk Consulting Ltd. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "DummyClassForUIView.h"
@interface DummyClassForUISlider : DummyClassForUIView {
float sliderValue;
}
- (void)setValue:(float)value animated:(BOOL)animated setNeedsDisplay: (BOOL) display;
@property (nonatomic,assign) float sliderValue;
@end
//
// DummyClassForUISlider.m
// WikiWikiServer
//
// Created by John M McIntosh on 10/09/09.
// Copyright 2009 Corporate Smalltalk Consulting Ltd. All rights reserved.
//
#import "DummyClassForUISlider.h"
@implementation DummyClassForUISlider
@synthesize sliderValue;
- init {
[super init];
sliderValue = 0.0;
return self;
}
- (void)setValue:(float)value animated:(BOOL)animated setNeedsDisplay: (BOOL) display {
sliderValue = value;
if (self.cell) {
if ([NSThread isMainThread]) {
[((UISlider *)self.cell) setValue: value animated: animated];
[self setNeedsDisplay: display];
} else {
NSAutoreleasePool * pool = [NSAutoreleasePool new];
NSMethodSignature* methodSignature = [((UISlider *)self.cell) methodSignatureForSelector:@selector(setValue:animated:)];
NSInvocation *redrawInv = [NSInvocation invocationWithMethodSignature: methodSignature];
[redrawInv setTarget: self.cell];
[redrawInv setSelector:@selector(setValue:animated:)];
[redrawInv setArgument: &value atIndex: 2];
[redrawInv setArgument: &animated atIndex: 3];
[redrawInv performSelectorOnMainThread: @selector(invoke) withObject: nil waitUntilDone: NO];
[pool drain];
}
}
}
@end
%%
But now you have the Squeak VM waiting in the ObjectiveCBridge code for the main thread to complete, but you have the main thread waiting on the SqueakProxy instance lock to complete as it waits for VM which can't run to respond. A classic deadlock situation.
To avoid this here are some code samples which you setup in applicationDidLaunch: as proxy to either a UITextLabel or UISlider.
The thought is you can either set the text or value, and the proxy looks after sending the data to UITextLabel to UISlider if it exists.
Exists? Yes a problem is that when a memorywarning message is sent to a UIViewController it can dispose of all the UIViews. So
in viewDidLoad: you basically ask the proxy for the data to use for initializing your UITextLabel. Technically you would have to ask
the Squeak VM for the data, but having it shared in the proxy makes this task much easier. But you then must remember to only
get/put data via the proxy, versus tampering with the data in the actual UITextLabel.
Usage:
A DummyClassForTextData may point to
text an NSString* for the UILabel text
placeHolder an NSString* for the UILabel placeHolder
cell the UIView object
DummyClassForUISlider may point to
sliderValue the slider value
cell the UIView object
The methods
setNeedsDisplay to send the setNeedsDisplay message to cell on the main thread no wait.
setTextAndPassThru:setNeedsDisplay: to set the text for the text property and pass that data to the cell.text, also the optional send of setNeedsDisplay
setPlaceHolderAndPassThru:setNeedsDisplay: to set the text for the placeHolder property, on the main thread, no wait.
getText to get the text
text
placeHolder
For the slider you have
setNeedsDisplay to send the setNeedsDisplay message to cell on the main thread no wait.
setValue:animated:setNeedsDisplay: to set the value and do the optional setNeedsDisplay logic on the main thread, no wait.
sliderValue to get the slider value
In future I'll provide a solution to allow you to get the slider value and text/placeHolder data from the cell object on the background
thread. This requires a bit more work since we need to use a Smalltalk external semaphore to make the VM wait until the NSInvocation populates
the instance's property variable.
%%(language-ref)
//
// DummyClassForUIView.h
// WikiWikiServer
//
// Created by John M McIntosh on 14/09/09.
// Copyright 2009 Corporate Smalltalk Consulting Ltd. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface DummyClassForUIView : NSObject {
NSObject *cell;
}
- (void)setNeedsDisplay;
- (void) setNeedsDisplay: (BOOL) display;
@property (nonatomic,assign) NSObject *cell;
@end
//
// DummyClassForUIView.m
// WikiWikiServer
//
// Created by John M McIntosh on 14/09/09.
// Copyright 2009 Corporate Smalltalk Consulting Ltd. All rights reserved.
//
#import "DummyClassForUIView.h"
@implementation DummyClassForUIView
@synthesize cell;
- (void)setNeedsDisplay {
[self setNeedsDisplay: YES];
}
- (void)setNeedsDisplay: (BOOL) display {
if (!self.cell) return;
if (!display) return;
if ([NSThread isMainThread])
[(UIView *) self.cell setNeedsDisplay];
else
[self.cell performSelectorOnMainThread: @selector(setNeedsDisplay) withObject: nil waitUntilDone: NO];
}
@end
//
// DummyClassForTextData.h
// WikiWikiServer
//
// Created by John M McIntosh on 10/09/09.
// Copyright 2009 Corporate Smalltalk Consulting Ltd. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "DummyClassForUIView.h"
@interface DummyClassForTextData : DummyClassForUIView {
NSString *text;
NSString *placeholder;
}
- (NSString *) getText;
- (void) setTextAndPassThru: (NSString *) aString setNeedsDisplay: (BOOL) display;
- (void) setPlaceHolderAndPassThru: (NSString *) aString setNeedsDisplay: (BOOL) display;
@property (nonatomic,retain) NSString *text;
@property (nonatomic,retain) NSString *placeholder;
@end
//
// DummyClassForTextData.m
// WikiWikiServer
//
// Created by John M McIntosh on 10/09/09.
// Copyright 2009 Corporate Smalltalk Consulting Ltd. All rights reserved.
//
#import "DummyClassForTextData.h"
@implementation DummyClassForTextData
@synthesize text,placeholder;
- (void) setPlaceHolderAndPassThru: (NSString *) aString setNeedsDisplay: (BOOL) display {
self.placeholder = aString;
if (self.cell) {
if ([NSThread isMainThread]) {
((UITextField *)self.cell).placeholder = aString;
} else {
[self.cell performSelectorOnMainThread: @selector(setPlaceholder:) withObject: aString waitUntilDone: NO];
}
[self setNeedsDisplay: display];
}
}
- (void) setTextAndPassThru: (NSString *) aString setNeedsDisplay: (BOOL) display {
self.text = aString;
if (self.cell) {
if ([NSThread isMainThread]) {
((UITextField *)self.cell).text = aString;
} else {
[self.cell performSelectorOnMainThread: @selector(setText:) withObject: aString waitUntilDone: NO];
}
[self setNeedsDisplay: display];
}
}
- (NSString *) getText {
return self.text;
}
@end
//
// DummyClassForUISlider.h
// WikiWikiServer
//
// Created by John M McIntosh on 10/09/09.
// Copyright 2009 Corporate Smalltalk Consulting Ltd. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "DummyClassForUIView.h"
@interface DummyClassForUISlider : DummyClassForUIView {
float sliderValue;
}
- (void)setValue:(float)value animated:(BOOL)animated setNeedsDisplay: (BOOL) display;
@property (nonatomic,assign) float sliderValue;
@end
//
// DummyClassForUISlider.m
// WikiWikiServer
//
// Created by John M McIntosh on 10/09/09.
// Copyright 2009 Corporate Smalltalk Consulting Ltd. All rights reserved.
//
#import "DummyClassForUISlider.h"
@implementation DummyClassForUISlider
@synthesize sliderValue;
- init {
[super init];
sliderValue = 0.0;
return self;
}
- (void)setValue:(float)value animated:(BOOL)animated setNeedsDisplay: (BOOL) display {
sliderValue = value;
if (self.cell) {
if ([NSThread isMainThread]) {
[((UISlider *)self.cell) setValue: value animated: animated];
[self setNeedsDisplay: display];
} else {
NSAutoreleasePool * pool = [NSAutoreleasePool new];
NSMethodSignature* methodSignature = [((UISlider *)self.cell) methodSignatureForSelector:@selector(setValue:animated:)];
NSInvocation *redrawInv = [NSInvocation invocationWithMethodSignature: methodSignature];
[redrawInv setTarget: self.cell];
[redrawInv setSelector:@selector(setValue:animated:)];
[redrawInv setArgument: &value atIndex: 2];
[redrawInv setArgument: &animated atIndex: 3];
[redrawInv performSelectorOnMainThread: @selector(invoke) withObject: nil waitUntilDone: NO];
[pool drain];
}
}
}
@end
%%