RestKit: Multiple RKClients / Changing baseURL - restkit

I initialize RKClient's sharedClient in my application delegate in applicationDidFinishLaunching and it works great. I am using this clients destination URL for most of the application, however at 1 point, in 1 class (Player), I need to load user's avatars from gravatar.com. So, I had the Player class define it's own RKClient and conform to the RKRequestDelegate protocol. It then makes the request, through this new RKClient instantiation and sets the delegate of the request to self. The problem is that I never receive a response; that is
- (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response
Is never called. Here is the whole code sample:
// Player.m
#import "Player.h"
#implementation Player
# pragma mark - Accessor Synthesizers
#synthesize identifier = _identifier;
#synthesize name = _name;
#synthesize story = _story;
#synthesize emailHash = _emailHash;
#synthesize pointPercentage = _pointPercentage;
#synthesize hitPercentage = _hitPercentage;
#synthesize lastCups = _lastCups;
#synthesize shotCount = _shotCount;
#synthesize hitCount = _hitCount;
#synthesize wins = _wins;
#synthesize losses = _losses;
#synthesize gravatar = _gravatar;
# pragma mark - Instance Methods
- (void)getGravatar {
RKClient *gClient = [RKClient clientWithBaseURL:[NSURL URLWithString:#"http://gravatar.com"]];
NSString *path = [self gravatarLink];
NSLog(#"Getting Gravatar With Link: http://gravatar.com%#", path);
[gClient get:path delegate:self];
}
- (NSString *)description {
return [NSString stringWithFormat:#"{Season: [id=%i, name=%#, story=%# ]}", _identifier, _name, _story];
}
# pragma mark - RKRequest Delegate Methods
- (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response {
NSLog(#"Gravatar Back: %#", response.bodyAsString);
self.gravatar = response.body;
[[NSNotificationCenter defaultCenter] postNotificationName:#"GravatarLoaded" object:self];
}
# pragma mark - Private Methods
- (NSString *)gravatarLink {
NSString *path;
path = [NSString stringWithFormat:#"/avatar/%#?d=monsterid&r=x", _emailHash];
if([[UIScreen mainScreen] respondsToSelector:#selector(scale)] && [[UIScreen mainScreen] scale]==2)
return [path stringByAppendingString:#"&s=200"];
else
return [path stringByAppendingString:#"&s=100"];
}
#end
Also, I have tried changing the base URL of the sharedClient and just using the sharedClient for the gravatar requests. But whenever I try to change the baseURL property of the RKClient sharedClient, either of these ways:
[[RKClient sharedClient] setBaseURL:[NSURL URLWithString:#"http://gravatar.com"]];
or
[RKClient sharedClient].baseURL: [NSURL URLWithString:#"http://gravatar.com"];
I get a runtime error:
2012-04-07 15:37:23.565 MLP[34403:fb03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSURL URLByAppendingResourcePath:queryParameters:]: unrecognized selector sent to instance 0x8bcdd50'
*** First throw call stack:
(0x1b7c022 0x1f58cd6 0x1b7dcbd 0x1ae2ed0 0x1ae2cb2 0x23eb5 0x24032 0x6ddb 0xdda2 0xc465c5 0xc467fa 0x14db85d 0x1b50936 0x1b503d7 0x1ab3790 0x1ab2d84 0x1ab2c9b 0x20407d8 0x204088a 0xbb5626 0x27cd 0x2735)
terminate called throwing an exception(lldb)

I used:
[[RKClient sharedClient] setBaseURL:[RKURL URLWithString:#"http://gravatar.com"]];
That worked for me.

The clientWithBaseURL: method expects an NSString, not a NSURL. Try to use
[[RKClient sharedClient] setBaseURL:#"http://gravatar.com"];

you just need to go to Targets-> build Settings —> other Linker Flags
As specified in the RestKit Tutorial we changed added a flag called “-ObjC-all_load” now edit that to just display “-ObjC”
this must wok for you.

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

Programmatically tagging in Mavericks from an Sandboxed App

I am writing to a file in an sandboxed app and later trying to set the tags for it using -[NSURL setResourceValue:theTags forKey:NSURLTagNamesKey error:&theTaggingError];. I am not getting any errors (i.e, tags are successfully applied once) but eventually file is kind of replaced and tags are lost. This is only in sandboxed app; if I turn off sandboxing things work fine. In sandboxed mode, if I set tags without writing to the file - again things work fine.
In essence, I am unable to set tags of a file after writing to it. How can I fix it? Any insights?
Sample Code:
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
{
NSWindow *_window;
NSURL *_saveURL;
NSSavePanel *_savePanel;
}
#property (assign) IBOutlet NSWindow *window;
#property (retain) NSURL *saveURL;
#property (retain) NSSavePanel *savePanel;
- (IBAction)writeAndTag:(id)sender;
- (IBAction)justTag:(id)sender;
#end
#implementation AppDelegate
#synthesize window = _window;
#synthesize saveURL = _saveURL;
#synthesize savePanel = _savePanel;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
self.savePanel = [NSSavePanel savePanel];
}
- (IBAction)writeAndTag:(id)sender
{
[self.savePanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) {
self.saveURL = [self.savePanel URL];
NSString *testString = #"Hello!";
NSError *error = nil;
[testString writeToFile:[self.saveURL path] atomically:NO encoding:NSUTF8StringEncoding error:&error];
if(error)
{
NSLog(#"Err in saving: %#" ,error);
error = nil;
}
// Tag is lost here
BOOL success = [self.saveURL setResourceValue:[NSArray arrayWithObjects:#"Test", nil] forKey:NSURLTagNamesKey error:&error];
NSLog(#"Tagging success: %#", (success)?#"YES":#"NO");
if(error)
{
NSLog(#"Err in tagging: %#" ,error);
}
}];
}
- (IBAction)justTag:(id)sender
{
// Works fine
[self.saveURL setResourceValue:[NSArray arrayWithObjects:#"Test", nil] forKey:NSURLTagNamesKey error:NULL];
}
#end

linking dictionary to custom initialiser terminating - reason: '-[__NSCFArray isFileURL]:

please be patient im a nuubie at this
I'm writing a custom init for first time, the sentance01text loads fine so i know the plist is reading ok :) but i cant seem to get my sentance01Timing timings to work ><
this method should pass the sentance01Timing typed by the user which is the objectForKey which should load the relevant array into the audioIntervals array
at the moment I'm using an NSString to access the dictionary and pass this to the array audiointervals
but this seems to be wrong and causes the error anyhelp would be appreciated.
i dont understand why it worked for the text but not this?
terminating - reason: '-[__NSCFArray isFileURL]:
probably Im doing something really dumb >< please help if you can
ps am having to use my old mac (my nice one is being repaired at the moment - so will be using non arc - then updating the code when I get my nice mac back, so just keep it in mind
its why im not releasing any objects at the moment...)
HelloWorld.m
#import "HelloWorldLayer.h"
#import "TextWithAudioHilight.h"
#implementation HelloWorldLayer
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if( (self=[super init])) {
TextWithAudioHilight *pagetext = [[TextWithAudioHilight alloc]initWith5:#"test words here,\nmore words, more words.."
sentance01Timing:#"TimingSEN01"
withSoundNamed:nil];
[self addChild:pagetext];
}
return self;
}
- (void) dealloc
{
[super dealloc];
}
#end
TextWithAudio.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface TextWithAudioHilight : CCLayer {
}
#property(nonatomic,retain)NSString *sentance01text;
#property(nonatomic,retain)NSString *sentance01Timing;
#property(nonatomic,retain)NSString *soundNamed;
-(id)initWith5:(NSString *)sentance01text sentance01Timing:(NSString *)sentance01Timing withSoundNamed:(NSString *)soundNamed;
#end
TextWithAudio.m
#import "TextWithAudioHilight.h"
#implementation TextWithAudioHilight
#synthesize sentance01text = _sentance01text;
#synthesize sentance01Timing = _sentance01Timing;
#synthesize soundNamed = _soundNamed;
-(id)initWith5:(NSString *)sentance01text sentance01Timing:(NSString *)sentance01Timing withSoundNamed:(NSString *)soundNamed
{
self = [super init];
if(self)
{
CGSize size = [[CCDirector sharedDirector] winSize];
NSString* plistPath = [[NSBundle mainBundle] pathForResource:#"AudioTimings" ofType:#"plist"];
NSDictionary* myDictionary = [NSDictionary dictionaryWithContentsOfFile:plistPath];
//needs create array that has timing information as an array from the plist
//NSString *Text01timing = [myDictionary objectForKey:#"sentance01Timing"];
NSString *Text01timing = [myDictionary objectForKey:_sentance01Timing];
NSMutableArray * audioIntervals = [NSMutableArray arrayWithContentsOfFile:Text01timing];
NSLog(#"Text01timing %f",audioIntervals);
//needs to create a label and put the text in it
CGSize maxSize = {800, 200};
CGSize actualSize = [sentance01text sizeWithFont:[UIFont fontWithName:#"Helvetica" size:20]
constrainedToSize:maxSize lineBreakMode:UILineBreakModeWordWrap];
CGSize containerSize = { actualSize.width, actualSize.height };
CCLabelTTF *label = [CCLabelTTF labelWithString:sentance01text dimensions:containerSize
alignment:UITextAlignmentLeft fontName:#"Helvetica"
fontSize:20];
// Center label
label.position = ccp( size.width /2 , size.height/6 );
label.color = ccc3(80, 80, 80);
// Add label to this scene
[self addChild:label z:7];
}
return self;
}
#end
AudioTimings.plist
<plist version="1.0">
<dict>
<key>TimingSEN01</key>
<array>
<real>0.044444</real>
<real>0.143054</real>
<real>0.213886</real>
<real>0.48055</real>
<real>0.844434</real>
<real>1.345817</real>
<real>1.470816</real>
<real>1.577759</real>
<real>2.020809</real>
<real>2.331917</real>
</array>
</dict>
</plist>
With many thanks to trojanfoe I was able to fix the problem
the main problem was that my initialised objects wernt retained
if you do see a better way of things in the code please say as my goal is to learn (but baby steps! its all pretty new!!)
im doing this on my old mac laptop (so its not for arc - as i cant test it at the moment)
but maybe it will help someone else...
so creating my textmangerclass:
#interface TextManagerWithpageNum : CCLayer
{
//create the properties you need notice the underscore
//NSString *_varName;
NSString *_background;
NSString* _text; //myText
NSString* _soundFile;
NSString* _audioInterval;
NSString* _currPageNumber;
}
declare the #property which gives access to the value accessor (getter) and mutator (setter)
//#property(nonatomic, strong)NSString* background; - in arc
#property(nonatomic, retain) NSString* background;
#property(nonatomic, retain) NSString* text;
#property(nonatomic, retain) NSString* soundFile;
#property(nonatomic, retain) NSString* audioInterval;
#property(nonatomic, retain) NSString* currPageNumber;
and implementation .m
//#synthesize varName = _varName;
#synthesize background = _background;
#synthesize text = _text;
#synthesize soundFile = _soundFile;
#synthesize audioInterval = _audioInterval;
#synthesize currPageNumber = _currPageNumber;
-(id)initWithBackground:(NSString *)background
textFromPlist:(NSString *)text
soundNamed:(NSString *)soundFile
audioIntervalPlist:(NSString *)audioInterval
CurrentPage:(NSString *)currPageNumber
{
self = [super init];
if(self)
{
//_varName = varName;
_text = text;
_audioInterval = audioInterval;
_soundFile = soundFile;
_currPageNumber = currPageNumber;
/*here is where I was having the problem - its important to manually retain
and dealloc or you wont be able to use your objects created!*/
//audio interval
_audioInterval= [[myDictionary objectForKey:audioInterval]retain];//***please retain me! and dont forget to dealloc! :)
NSLog(#"audio Intervals %#",audioInterval);
hello world
TextManagerWithpageNum *Mypage =
[[TextManagerWithpageNum alloc]initWithBackground:#"Page01Bg.png"textFromPlist:#"Page01Text"soundNamed:#"Page01" audioIntervalPlist:#"AudioTimings" CurrentPage:5];
[self addChild:Mypage];
//hope the practicle example of where i stuffed up helps someone else
since its more fun to learn by someone elses mistakes :P

NSMutableData setLength:NSUInteger crashing the app

Trying to create a connection of a request with an URL. An NSMutableData instance (responseData) also gets called with it. When the connection starts receiving response, the setLength:NSUInteger method gets called up on the NSMutableData Instance.
-(void)startDataDownloading
{
NSURLRequest *_request = [NSURLRequest requestWithURL:self.url];
if (_request) {
if (!connecton) {
connecton = [NSURLConnection connectionWithRequest:_request delegate:self];
if (connecton) {
responseData = [NSMutableData data];
[connecton start];
}
}
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
But somehow it causes a crash with a warning on the setLength call. The error states that
" -[__NSCFDictionary setLength:]: unrecognized selector sent to instance 0x6a8cf70
2012-11-30 18:00:38.948 RSSReader[8997:f803] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary setLength:]: unrecognized selector sent to instance 0x6a8cf70' "
Any hint about this would be appreciated.
#import <Foundation/Foundation.h>
#import "DataParser.h"
#protocol DataConnectionDelegate <NSObject>
//protocol methods
#end
#interface UCDataConnection : NSObject <ModelParser>
#property (nonatomic, strong) NSURL *url;
#property (nonatomic, strong) NSURLConnection *connecton;
#property (strong, nonatomic) NSMutableData *responseData;
#property (nonatomic, assign) id<DataConnectionDelegate> delegate;
-(void)startDataDownloading;
- (id)initWithUrl:(NSURL *)_url andDelegate:(id<DataConnectionDelegate>)_delegate;
That is a part of the header file.Sorry for late response.
Most likely you're not retaining responseData correctly, so it's being released and in your above example you happen to end up getting an NSDictionary allocated in the same place.
If you're using ARC then the code you posted is fine (other than that "responseData" should probably have an underscore prefix, assuming it's an instance variable).
If you're using retain-release, then you need to add a call to retain when you allocate responseData.
Update: Based on your header file it looks like you're referring to the instance variable directly, and using retain-release. Your best option is to refer to responseData only through the property mechanism - i.e. prefix all its uses with self..
I don't know if this is the answer, but what I see suspicious here is that you have a property
#property (strong, nonatomic) NSMutableData *responseData;
and by default it should be accessed with self. responseData;
if you intend to access private ivar you should by default use _responseData.
Unless you said differently in .m file which I would also like to see, so to be sure what's going on (in case this answer won't help).

NSMutableDictionary setObject:forKey - custom class

I am using this in a UINavigation environment.
I have customClassA. It inherits customClassB and one of its object is a NSMutableDictionary.
I alloc and init customClassA in a viewController, then for adding data, I am pushing a new viewController into the stack. The addNewDataViewController sends the newly added data, a customClassB object back by its delegate. Everything works fine so far.
customClassA has to store the returned object (customClassB) into its NSMutableDictionary object with a key (an NSString created from NSDate).
I get "mutating method sent to immutable object" error and can't think of any solution.
Any help is appreciated.
Thanks.
===========================
interface customClassA : NSObject
{
NSDate date;
NSArray *array; // will contain only NSString objects
}
// and the rest as customary
...
#import "customClassA.h"
interface customClassB : NSObject
{
NSString *title;
NSMutableDictionary *data; // will contain values of customClassA with keys of NSString
}
// and the rest as customary
...
#import "customClassB"
#interface firstViewController : UITableViewController <SecondViewControllerDelegate>
- (void)viewDidLoad
{
self.customClassB_Object = [customClassB alloc] init];
// and the rest...
}
- (void)secondViewControllerDidSaveData:(customClassA *)aData
{
[self.customClassB_Object.data setObject:aData forKey:[NSString stringWithFormat:#"%#", aData.date]];
// update tableView
}
Make sure you are initializing the NSMutableDictionary with something like
NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init];
It would appear that your NSMutableDictionary is getting created with an NSDictionary instance instead of a NSMutableDictionary
Althoguh I added the following code to customClassB implementation, it still didn't work.
#implementation customClassB
- (id)init
{
self = [super init];
if (self)
self.data = [NSMutableDictionary alloc] init];
return self;
}
so I added two custom methods to my customClassB implementation, as well as in the header file:
- (void)appendData:(customClassA *)aData;
- (void)removeDataWithKey:(NSString *)aKey;
and instead of manipulating the data dicionary of customClassB in my viewController, I simply call that method and pass the data object to the class and it did the trick.

Resources