RestKit doesn't send second request - restkit

RestKit doesn't send second request
I have a simple application with 1 view and 2 buttons
titles of buttons are hostnames (yandex.ru and localhost:3000)
when i click on any button at first time
request works
but if i click second time on any it doesn't send it....
what do i do wrong?
below is part of code of my ViewController
- (IBAction)testRestkit:(UIButton *)sender
{
RKClient *client =[RKClient clientWithBaseURLString:[NSString stringWithFormat:#"http://%#",sender.titleLabel.text]];
client.cachePolicy = RKRequestCachePolicyNone;
[client get:nil delegate:self];
}
- (void)requestWillPrepareForSend:(RKRequest *)request
{
NSLog(#"Preparing for request......");
}
- (void)request:(RKRequest *)request didFailLoadWithError:(NSError *)error
{
NSLog(#"%#",[error localizedDescription]);
}
- (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response
{
if ([response isHTML]) {
NSLog(#"Loaded html!");
} else{
NSLog(#"Loaded some response!");
}
}

if i send request like code below . they works!!!!
someone could explain difference between both methods???
- (IBAction)testRestkit:(UIButton *)sender
{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://%#",sender.titleLabel.text]];
RKRequest *theRequest = [[RKRequest alloc] initWithURL:url];
theRequest.queue = [RKClient sharedClient].requestQueue;
theRequest.delegate = self;
[theRequest setMethod:RKRequestMethodGET];
[theRequest send];
}

I think the problem is that the first time you call clientWithBaseURLString:, an [RKClient sharedClient] singleton is initialized (and properly retained), so the subsequent call does work. When you invoke the code for the second time, the convenience constructor returns an autoreleased instance of RKClient with the another base url.
The correct way to handle multiple base URLs in RestKit is to manage two, separate instances of RKClient, e.g.
#property (nonatomic, retain) RKClient *localhostClient;
#property (nonatomic, retain) RKClient *remoteClient;
and initialize them eg. in your init method (or lazily in your method).
static NSString *kRemoteServerUrl = #"http://yandex.ru";
- (IBAction)testRestkit:(UIButton *)sender
{
RKClient *client = nil;
if ([sender.titleLabel.text isEqualToString:kRemoteServerUrl]) {
if (!self.remoteClient) {
self.remoteClient = [RKClient clientWithBaseURLString:kRemoteServerUrl];
client.cachePolicy = RKRequestCachePolicyNone;
}
[self.remoteClient get:nil delegate:self];
} else if (.....)
....
}

Related

XPC Between two cocoa applications in workspace, the NSXPCConnection is immediately being invalidated

I have two Cocoa Applications, one is going to be the sender and another the receiver in this XPC relationship.
In the applicationDidFinishLaunching in the sender, I first open the second receiver application
NSError* error = nil;
NSURL* url = [[NSBundle mainBundle] bundleURL];
url = [url URLByAppendingPathComponent:#"Contents" isDirectory:YES];
url = [url URLByAppendingPathComponent:#"MacOS" isDirectory:YES];
url = [url URLByAppendingPathComponent:#"TestXPCHelper.app" isDirectory:YES];
[[NSWorkspace sharedWorkspace] launchApplicationAtURL:url
options:NSWorkspaceLaunchWithoutActivation
configuration:[NSDictionary dictionary]
error:&error];
if ( error )
{
NSLog(#"launchApplicationAtURL:%# error = %#", url, error);
[[NSAlert alertWithError:error] runModal];
}
Then I create my NSXPCConnection
assert([NSThread isMainThread]);
if (self.testConnection == nil) {
self.testConnection = [[NSXPCConnection alloc] initWithMachServiceName:NEVER_TRANSLATE(#"com.TechSmith.TestXPCHelper") options:NSXPCConnectionPrivileged];
self.testConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:#protocol(TestXPCProtocol)];
self.testConnection.interruptionHandler = ^{
NSLog(#"Connection Terminated");
};
self.testConnection.invalidationHandler = ^{
self.testConnection.invalidationHandler = nil;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.testConnection = nil;
}];
};
[self.testConnection resume];
}
Then I try to send a message over the connection (the connection is already invalidated by here)
id<TestXPCProtocol> testRemoteObject= [self.testConnection remoteObjectProxy];
[testRemoteObject testXPCMethod2];
[[self.testConnection remoteObjectProxyWithErrorHandler:^(NSError * proxyError){
NSLog(#"%#", proxyError);
}] testXPCMethod:^(NSString* reply) {
NSLog(#"%#", reply);
}];
And here is the app delegate for my receiver application:
#interface AppDelegate () <NSXPCListenerDelegate, TestXPCProtocol>
#property (weak) IBOutlet NSWindow *window;
#property NSXPCListener *xpcListener;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
NSLog(#"TESTING123");
self.xpcListener = [[NSXPCListener alloc] initWithMachServiceName:#"com.TechSmith.TestXPCHelper"];
self.xpcListener.delegate = self;
[self.xpcListener resume];
}
- (void)applicationDidBecomeActive:(NSNotification *)notification {
NSLog(#"ACTIVE234");
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
- (void)run
{
NSLog(#"RUNNING");
// Tell the XPC listener to start processing requests.
[self.xpcListener resume];
// Run the run loop forever.
[[NSRunLoop currentRunLoop] run];
}
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
{
NSLog(#"LISTENING");
assert(listener == self.xpcListener);
#pragma unused(listener)
assert(newConnection != nil);
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:#protocol(TestXPCProtocol)];
newConnection.exportedObject = self;
[newConnection resume];
return YES;
}
- (void)testXPCMethod:(void(^)(NSString * version))reply
{
NSLog(#"HEY");
reply(#"REPLY HERE");
}
- (void)testXPCMethod2
{
NSLog(#"TWO!");
}
Here is the proxyError when I try to send a message over the connection:
Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service
named com.TechSmith.TestXPCHelper was invalidated." UserInfo={NSDebugDescription=The
connection to service named com.TechSmith.TestXPCHelper was invalidated.}
So I think I am doing something wrong with my instantiation of the NSXPCConnection. I can't find a good example of two applications speaking to eachother-- it's always one application and a service. Is that what my problem is? I need a service inbetween the applications talking?
Is there any way to get more information on why this connection is being invalidated? That would also help a lot
So pretty straight forward problem here,
Turns out initWithMachServiceName is explicitly looking for a mach service. I was using an identifier of another application process.
If I actually use an identifier of a valid mach service, there is no issue
Note that there are two other ways to create an NSXPCConnection,
with an NSXPCEndpoint or with a XPCService identifier

Why do NSFilePresenter protocol methods never get called?

I am trying to monitor file changes in local and iCloud directories and have implemented the NSFilePresenter protocol methods but the only method that gets called is presentedItemAtURL.
Am I correct in assuming that I should be able to monitor a local or an iCloud directory and get notified any time any process adds, modifies or deletes a file in the directory.
Here is the basic code for the OS X App:
- (void)awakeFromNib {
_presentedItemURL = myDocumentsDirectoryURL;
_presentedItemOperationQueue = [[NSOperationQueue alloc] init];
[_presentedItemOperationQueue setMaxConcurrentOperationCount: 1];
_fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:self];
}
- (NSURL*) presentedItemURL {
FLOG(#" called %#", _presentedItemURL);
return _presentedItemURL;
}
- (NSOperationQueue*) presentedItemOperationQueue {
FLOG(#" called");
return _presentedItemOperationQueue;
}
- (void)presentedItemDidChange {
FLOG(#" called");
dispatch_async(dispatch_get_main_queue(), ^{
[self reloadData];
});
}
-(void)accommodatePresentedItemDeletionWithCompletionHandler:(void (^)(NSError *errorOrNil))completionHandler
{ FLOG(#" called");
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self reloadData];
}];
completionHandler(nil);
}
-(void)presentedSubitemDidChangeAtURL:(NSURL *)url {
FLOG(#" called");
dispatch_async(dispatch_get_main_queue(), ^{
[self reloadData];
});
}
-(void)presentedSubitemDidAppearAtURL:(NSURL *)url {
FLOG(#" called");
dispatch_async(dispatch_get_main_queue(), ^{
[self reloadData];
});
}
Long time ago, I know, but perhaps this will still help. NSFilePresenter will only notify you about changes made by another process that makes changes to a directory or file USING AN NSFileCoordinator. If another process (eg: iTunes file sharing) makes changes without an NSFileCoordinator, you won't be notified.
This is in no way my final implementation and I will edit/update as I improve. But since there is nil examples on how to do this, i figured i'd share something that works!!! That's right, it works. I am able to read the file in my app, and at the same time make a change in textedit and the changes propagate to my app. Hope this helps bud.
PBDocument.h
#interface PBDocument : NSObject <NSFilePresenter>
#property (nonatomic, strong) NSTextView *textView;
#pragma mark - NSFilePresenter properties
#property (readonly) NSURL *presentedItemURL;
#property (readonly) NSOperationQueue *presentedItemOperationQueue;
- (instancetype)initWithContentsOfURL:(NSURL *)url error:(NSError *__autoreleasing *)outError textView:(NSTextView*)textView;
#end
PBDocument.m
#interface PBDocument ()
#property (readwrite) NSURL *presentedItemURL;
#property (readwrite) NSOperationQueue *presentedItemOperationQueue;
#property (readwrite) NSFileCoordinator *fileCoordinator;
#end
#implementation PBDocument
- (instancetype)initWithContentsOfURL:(NSURL *)url error:(NSError *__autoreleasing *)outError textView:(NSTextView*)textView {
self = [super init];
if (self) {
_textView = textView;
_presentedItemURL = url;
_presentedItemOperationQueue = [NSOperationQueue mainQueue];
[NSFileCoordinator addFilePresenter:self];
_fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:self];
[self readWithCoordination];
}
return self;
}
- (void)readWithCoordination {
NSError *error = nil;
[self.fileCoordinator coordinateReadingItemAtURL:_presentedItemURL options:NSFileCoordinatorReadingWithoutChanges error:&error byAccessor:^(NSURL *newURL) {
NSLog(#"Coordinating Read");
NSError *error = nil;
NSFileWrapper *wrapper = [[NSFileWrapper alloc] initWithURL:newURL options:0 error:&error];
if (!error) {
[self readFromFileWrapper:wrapper ofType:[self.presentedItemURL pathExtension] error:&error];
}
if (error) #throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:#"%#", error] userInfo:nil];
}];
if (error) #throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:#"%#", error] userInfo:nil];
}
- (void)presentedItemDidChange {
[self readWithCoordination];
}
#end
If it's any help to anyone this is the approach (FSEvents) I ended up using recently for a file sync solution and it seems to work for any file system. I have not done any research recently on NSFileCoordinator to see whether this is better worse or what the use cases are as a comparison.
I also did not test every use case so your mileage may vary.
https://github.com/eonil/FSEvents

RestKit iOS - Second Time fails

I'm using the RestKit for a simple request that returns JSON data.
I've implemented this code that works only the first time that the viewDidLoad is called, the second time the request is not performed. Why??
- (void)viewDidLoad
{
[super viewDidLoad];
[self planOtpTrip];
}
-(void) planOtpTrip{
NSLog(#"[INFO] planoOtpTrip");
client = [RKClient clientWithBaseURLString:#"http://myserver/opentripplanner-api-webapp/ws"];
[client setValue:#"application/json" forHTTPHeaderField:#"Accept"];
NSDictionary *queryParameters = [NSDictionary dictionaryWithObjectsAndKeys:#"45.028952,7.624598",#"fromPlace",#"45.06123,7.65981", #"toPlace",#"TRANSIT,WALK" ,#"mode", nil];
// Imposto il nome della API da richiamare
NSString *getResourcePath = RKPathAppendQueryParams(#"/plan", queryParameters);
[client get:getResourcePath delegate:self];
}
- (void)request:(RKRequest*)request didLoadResponse:(RKResponse*)response {
// where you handle response object
NSLog(#"Risposta ricevuta: %#", response.URL);
NSLog(#"Response Body: %#", response.bodyAsString);
id jsonParser = [[RKParserRegistry sharedRegistry] parserForMIMEType:RKMIMETypeJSON];
NSError *error = nil;
NSDictionary* parsedResponse = [jsonParser objectFromString:[response bodyAsString] error:&error];
if (error == nil)
{
NSLog(#"GET returned with HTTP Code %d and parsedContent: %#", [response statusCode], parsedResponse);
}
else
{
NSLog(#"Error: %#", error);
}
return [self renderResponse:parsedResponse];
}
I had this problem as well but i found a solution. Define the RKClient in your .h file like so:
#property (retain) RKClient *downloadClient;
Then in your .m file synthesize the downloadClient like so:
#synthesize downloadClient;
And then in your didLoadResponse method you release the downloadClient when your done with it, like so:
- (void)request:(RKRequest*)request didLoadResponse:(RKResponse*)response
{
//do something with your response
[downloadClient release];
}

Best way to implement RKReachabilityObserver in RestKit

I have written a tab based application in Xcode/RestKit and am attempting to use the RKReachabilityObserver to determine Internet connectivity on the device.
Ideally I'd like to have a single reachability variable throughout my application (if this is possible) but currently my implementation is as per the code below and does not work very well when replicated over my 4 tabs.
If anybody has any suggestions of a better way to do this, I'd really appreciate your comments.
View.h
#property (nonatomic, retain) RKReachabilityObserver *observer;
View.m
#interface AppViewController()
{
RKReachabilityObserver *_observer;
}
#property (nonatomic) BOOL networkIsAvailable;
#synthesize observer = _observer;
-(id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
self.observer = [[RKReachabilityObserver alloc] initWithHost:#"mydomain"];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reachabilityChanged:)
name:RKReachabilityDidChangeNotification
object:_observer];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// determine network availability
if (! [_observer isReachabilityDetermined]) {
_networkIsAvailable = YES;
}
else
{
_networkIsAvailable = NO;
}
_text.returnKeyType = UIReturnKeyDone;
_text.delegate = self;
}
- (void)reachabilityChanged:(NSNotification *)notification {
RKReachabilityObserver* observer = (RKReachabilityObserver *) [notification object];
if ([observer isNetworkReachable]) {
if ([observer isConnectionRequired]) {
_networkIsAvailable = YES;
NSLog(#"Reachable");
return;
}
}
else
{
_networkIsAvailable = NO;
NSLog(#"Not reachable");
}
}
then anywhere in my view, I simply do....
if (_networkIsAvailable == YES)
{...
I have implemented this over multiple views (which seems to be causing the problem.
What is the suggested approach for a multiple-view application?
The [RKClient sharedClient] singleton already has a property for that (reachabilityObserver). Feel free to use that one.
if ([[[RKClient sharedClient] reachabilityObserver] isReachabilityDetermined] && [[RKClient sharedClient] isNetworkReachable]) {
....
}
You can also subscribe to RKReachabilityObserver notifications (if you want to take any action when reachability status changes)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reachabilityStatusChanged:)
name:RKReachabilityDidChangeNotification object:nil];
Here is some changes in RestKit 0.20 and later.
The code of reachability block should looks like:
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[RemoteTools serverUrl]];
[manager.HTTPClient setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
if (status == AFNetworkReachabilityStatusNotReachable) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No network connection"
message:#"You must be connected to the internet to use this app."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}];

I need to return a string in cocoa after http request and xml delegates are complete?

I have the following delegate method of NSURLConnection
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"DONE, Receive bytes: %d", [webData length]);
NSString *theXML = [[NSString alloc]initWithBytes:[webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];
//NSLog(theXML);
[theXML release];
if(xmlParser)
{
[xmlParser release];
}
else
{
xmlParser = [[NSXMLParser alloc]initWithData:webData];
[xmlParser setDelegate:self];
[xmlParser setShouldResolveExternalEntities:YES];
[xmlParser parse];
[connection release];
[webData release];
NSLog(#"\n\n\n\n");
NSLog(httpResult);
}
I want to return httpResult - how do i do this? I have the above method in a class. I create an instance of this class in another controller class which calls a function to create an http request. This function then in turn calls this delegate method. How do i return httpResult to the controller class?
I have figured it out - thanks guys
Give that class either a delegate or a didFinish-type callback and set that to tell your controller when it's done.

Resources