Cocoa Frequently Asked Questions
- How to install a code generation template update?
- How to uninstall RO/DA completely from OS X system?
- Setting ROHTTPClientChannel channel timeout value seems to have no effect on iOS, why?
- Why am I getting 'symbol not found' linker errors when building an iOS application?
How to install a code generation template update?
Code generation template updates are being distributed sometimes to fix some issues before a new products version built. It's easy to install such update which may consist of one or more files with such names as:
- codegen2
- template.Obj-C.intf.h_
- template.Obj-C.intf.m_ Plase follow these steps to install them:
- locate the
rodl2objc
application with Finder at `/Developer/RemObjects Software/Tools - Ctrl-click the
rodl2objc
file and execute theShow Package Contents
command, the new Finder window will appear - Inside that new window navigate to the
Contents/Resources
path, you will see existing files with the names listed above - Drag the new copies of updated files to this window, they will be copied and will replace existing ones.
How to uninstall RO/DA completely from OS X system?
Actually you need to remove two directories, one contains the Xcode project templates and other contains the rest. Execute the following commands from Terminal (need to enter your password):
sudo rm -rf /Library/Developer/Xcode/Templates/Project\ Templates/*
sudo rm -rf /Developer/RemObjects\ Software
Setting ROHTTPClientChannel channel timeout value seems to have no effect on iOS, why?
This happens due to iOS SDK design, all attempts to set the HTTP timeout value lower than some minimum are ignored at the Foundation framework level. The reason of such behavior is that in slow network conditions (such as GSM/EDGE) short timeouts make no sense and lead to unnecessary timeout errors in applications.
If you still need short timeout values the only way to work this around is to use Asynchronous Requests in combination with NSTimer
objects. The idea is to start the request together with the timer programmed to fire after necessary timeout period. When the timer fires it will cancel the corresponding asynchronous request. Look into the following sample code.
- Header:
@interface iOS_HTTP_TimeoutViewController : UIViewController
{
// Assume two text fields to enter the request timeout and actual duration
UITextField *timeoutField;
UITextField *durationField;
// Instances necessary to access the remote server
ROBinMessage *msg;
ROClientChannel *chan;
SomeService_AsyncProxy *proxy;
}
@property (assign) IBOutlet UITextField *timeoutField;
@property (assign) IBOutlet UITextField *durationField;
// Will start the remote request in response to a button click
- (IBAction)start:(id)sender;
- (void)displayMessage:(NSString *)aMessage;
@end
- Implementation:
@implementation iOS_HTTP_TimeoutViewController
@synthesize timeoutField;
@synthesize durationField;
- (IBAction)start:(id)sender
{
int duration = [[durationField text] intValue];
int timeout = [[timeoutField text] intValue];
// This prepares the long operation with the specified timeout to start
// but doesn't start it yet.
ROAsyncRequest *asyncRequest = [proxy beginLongOp:duration start:NO];
asyncRequest.delegate = self;
// Notice the async request object passed as user info, will be used inside
// the 'timer fired' method
NSTimer *requestTimer = [NSTimer scheduledTimerWithTimeInterval:(double)timeout
target:self
selector:@selector(requestTimerFired:)
userInfo:asyncRequest
repeats:NO];
// The timer object itself is referenced by the async request for convenience,
// we have to cancel the timer in case of the operation finishes before the
// timeout expires.
asyncRequest.context = requestTimer;
[asyncRequest start];
}
- (void)requestTimerFired:(NSTimer*)aTimer
{
// The timeout expired - canceling the async request
[(ROAsyncRequest *)[aTimer userInfo] cancel];
}
- (void)displayMessage:(NSString *)aMessage
{
// Not so important ...
}
#pragma mark Async request delegate
- (void)asyncRequestDidComplete:(ROAsyncRequest *)request
{
// The operation completed - the timer is not needed any more
[(NSTimer *)request.context invalidate];
NSString *res = [proxy endLongOp:request];
[self displayMessage:[NSString stringWithFormat:@"Operation completed. %@", res]];
}
- (void)asyncRequest:(ROAsyncRequest *)request didFailWithException:(NSException *)exception
{
// The operation completed - the timer is not needed any more
[(NSTimer *)request.context invalidate];
[self displayMessage:[NSString stringWithFormat:@"Problem found... %@", [exception reason]]];
}
- (void)asyncRequestWasCanceled:(ROAsyncRequest *)request
{
[self displayMessage:@"Operation was cancelled by custom timeout"];
}
- (void)viewDidLoad
{
[super viewDidLoad];
msg = [[ROBinMessage alloc] init];
chan = [[ROHTTPClientChannel alloc] initWithTargetUrl:@"http://192.168.1.10:8099/bin"];
proxy = [[SomeService_AsyncProxy alloc] initWithMessage:msg channel:chan];
}
// Some not so important code not shown
@end
Why am I getting 'symbol not found' linker errors when building an iOS application?
The answer is also relevant for Data Abstract for Cocoa (iPhone OS version).
Both Remoting SDK for Cocoa and Data Abstract for Cocoa for iPhone OS are implemented as static libraries. Unlike Cocoa frameworks, static libraries contain no linking information inside. When a static library depends on a dynamic library (or framework, this makes no difference to the linker), the compiler generates all required code to call functions from the dynamic library but it doesn't (and should not) know where to get the functions code being called, this is the linker's task. But static libraries are not linked with dynamic ones when being built. That's why the linking information necessary to link an application to a dynamic library is lost when the dynamic library functions are used through static library wrappers.
So we have to provide all necessary linking information to our iPhone application manually.
At the moment two dynamic libraries are used by Remoting SDK:
libxml2.dylib
Security.framework
For future releases, additional libraries may be required. We are keeping this FAQ section up to date so if you encounter linker errors after Remoting SDK or Data Abstract upgrade please check this section for changes.
Referencing libxml2.dylib
The simplest way to reference libxml2
is to specify additional linker options. To do this navigate to your target Build Settings
in Xcode and locate the Other Linker Flags
parameter:
This is enough for the linker to locate the required libxml2.dylib
copy.
Referencing Security.framework
Go to your project's target settings in Xcode, navigate to Build Phases
and add Security.framework
to the Link Binary With Libraries
list: