Resolving NSNetService on server side - iphone

I have the problem in resolving NSNetService. i have successfully resolved NSNetService when NSNetServiceBrowser find that service.
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing{
if (![self.services containsObject:aNetService]) {
[aNetService setDelegate:self];
[aNetService resolveWithTimeout:5.0];
}
}
then this method is successfully called
-(void)netServiceDidResolveAddress:(NSNetService *)sender{
NSArray *addresses = [ns addresses];
NSDictionary* dict = [NSNetService dictionaryFromTXTRecordData:[sender TXTRecordData]];
// Here both values are ok
}
but i want to resolve NSNetService to server side to get the IP address on which that service is published.
-(void)netServiceDidPublish:(NSNetService *)ns{
[ns setDelegate:self];
[ns resolveWithTimeout:5.0];
}
but here this method is not calling.
-(void)netServiceDidResolveAddress:(NSNetService *)sender{
 
}
however i did this
-(void)netServiceDidPublish:(NSNetService *)ns
{
NSArray *addresses = [ns addresses]; // this gives null
// this also gives null
NSDictionary* dict = [NSNetService dictionaryFromTXTRecordData:[sender TXTRecordData]];
}
but values are null.
please help me if it is possible. any help will be appreciated. thanks in advance.

Had this problem the other day as well, and took me a while to figure it out.
For some reason, I needed to assign aNetService to a property.
# Declare a NSNetService property in the .h or further up .m file
#property (strong, nonatomic) NSNetService *currentService;
# In the .m file.
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing{
if (![self.services containsObject:aNetService]) {
self.currentService = aNetService;
[self.currentService setDelegate:self];
[self.currentService resolveWithTimeout:5.0];
}
}

Related

Bonjour NSNetServiceBrowser in iOS6 Not working

I'm working on advertising a desktop client to phones on the local network. My phone is at 6.0.2 with the Xcode 4.5.2.
I know the desktop app is registering successfully because the Discovery app (by Tildesoft) on my phone shows my service on the network (which also rules out wifi problems).
I've downloaded the Apple app example, Bonjour Web. The delegate for finding "_myservice._tcp" didn't ever fire, but the start browsing method does fire.
I tried using HHServices (which wraps DNSService), and while the start browsing method fired, the service found method doesn't fire.
In my own app, I tried using NSNetServiceBrowser. I set the delegate, and my "netServiceBrowserWillSearch" delegate method gets fired, but nothing else happens.
Code is attached if you want to verify.
Header:
#import <UIKit/UIKit.h>
#interface ClientFinder_ViewController : UIViewController<UITableViewDataSource, UITableViewDelegate,NSNetServiceBrowserDelegate>
#property (weak, nonatomic) IBOutlet UITableView *availableClientsTableView;
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindDomain:(NSString *)domainString moreComing:(BOOL)moreComing;
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing;
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didNotSearch:(NSDictionary *)errorDict;
-(void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)aNetServiceBrowser;
-(void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)aNetServiceBrowser;
#end
Relevant Implementation:
- (void)viewDidLoad
{
[super viewDidLoad];
dictionaryFoundClients = [[NSMutableDictionary alloc] initWithCapacity:1];
[self addLogoToNabar];
[self listen];
}
-(void)listen{
NSNetServiceBrowser *serviceBrowser = [NSNetServiceBrowser new];
[serviceBrowser setDelegate:self];
[self.netServiceBrowser searchForServicesOfType:TYPE inDomain:domain];
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindDomain:(NSString *)domainString moreComing:(BOOL)moreComing{
NSLog(#"aNetServiceBrowser didFindDomain");
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing{
NSLog(#"aNetServiceBrowser didFindService");
[dictionaryFoundClients setObject:aNetService forKey:aNetService.hostName];
NSLog(#"Found service: %# # %#", aNetService.name, aNetService.hostName);
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didNotSearch:(NSDictionary *)errorDict{
NSLog(#"aNetServiceBrowser didNotSearch. Errors enumerated");
for(int a=0; a< errorDict.count; a++){
NSString *key = [[errorDict allKeys] objectAtIndex:a];
NSString *val = [errorDict objectForKey:key];
NSLog(#"%#: %#", key, val);
}
}
-(void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)aNetServiceBrowser{
NSLog(#"netServiceBrowserDidStopSearch");
}
-(void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)aNetServiceBrowser{
NSLog(#"netServiceBrowserWillSearch");
}
If this is all local, you need to use searchForServicesOfType: method instead of searchForRegistrationDomains method.
-(void)listen{
NSNetServiceBrowser *serviceBrowser = [NSNetServiceBrowser new];
[serviceBrowser setDelegate:self];
[serviceBrowser searchForServicesOfType:#"_your_service_type._tcp" inDomain:#""];;
}
"_your_service_type._tcp" is the service type your desktop application is using when it advertises its service.
Not sure why it started working, but here is my working code:
[self stopCurrentResolve];
[self.netServiceBrowser stop];
[self.services removeAllObjects];
NSNetServiceBrowser *aNetServiceBrowser = [[NSNetServiceBrowser alloc] init];
if(!aNetServiceBrowser) {
// The NSNetServiceBrowser couldn't be allocated and initialized.
return NO;
}
aNetServiceBrowser.delegate = self;
self.netServiceBrowser = aNetServiceBrowser;
[self.netServiceBrowser searchForServicesOfType:type inDomain:domain];

IOS RESTKIT HTTP PUT example

I want to update data in server which runs in REST API. i am using RESTKIT from ios device. But i could not find how to use PUT in restkit.
I have to send data like key:"user_id" value:"2" these format. Can anyone please help me to solve this problem.. :(
SOKeyValue.h : serialized object used as parameter for your call.
#import <Foundation/Foundation.h>
#interface SOKeyValue : NSObject
#property (nonatomic, retain) NSString* key;
#property (nonatomic, retain) NSString* value;
#end
Here's a simplified code to initialize Restkit :
/*
This part of code must be executed only one time in your application
*/
//To see logs
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
//Init with good domain
RKObjectManager* manager = [RKObjectManager objectManagerWithBaseURL:#"http://mydomain.dev/ui/v1"];
//Indicate to use JSON
[RKObjectManager sharedManager].serializationMIMEType = RKMIMETypeJSON;
//Route path when you call a PUT with SOKeyValue class
[manager.router routeClass:[SOKeyValue class] toResourcePath:#"/yourpath" forMethod:RKRequestMethodPUT];
//Serialization for SOKeyValue class
RKObjectMapping* keyvalueSerializationMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class] ];
[authSerializationMapping mapAttributes:#"key", #"value", nil];
[[RKObjectManager sharedManager].mappingProvider setSerializationMapping:keyvalueSerializationMapping forClass:[SOKeyValue class] ];
Now we can implement a service who use PUT. In the object that will implement the call dont forget the restkit delegate RKObjectLoaderDelegate:
#import <Foundation/Foundation.h>
#import <RestKit/RestKit.h>
#import "SOKeyValue.h"
#interface MyViewOrMyServiceObject: NSObject <RKObjectLoaderDelegate>
- (void)putKeyValue;
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects;
- (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error;
#end
In your (.m) :
- (void)putKeyValue
{
SOKeyValue *keyvalue = [[SOKeyValue alloc] init];
keyvalue.key = #"k";
keyvalue.value = #"2";
[[RKObjectManager sharedManager] putObject:keyvalue delegate:self];
[keyvalue release];
}
You can see status code in your trace, and use callback functions :
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects;
- (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error;
So i dont have MAC at home, it's diffcult for help you about the code structure. If you have questions do not hesitate.

NSURL becomes null when passed as a parameter iphone

I have set up a couple of very simple methods that play with NSURLs and NSStrings.
the first method that gets called is getAudio. I want to set the variable audioPath equal to cleanAudio so that it can be used later in the encryptWithAudioFile. The problem is somewhere along the way when it is being passed as a parameter the object becomes null. I have no idea why and I have tried every method I can think of in terms of memory management to try and keep the object. The logs I have used work result as follows
NSLog(#"Clean Audio1: %#", audioPath); Perfect, works as it should NSLog(#"Clean Audio2: %#", audioPath); NSLog(#"Clean Audio3: %#", audioPath); NSLog(#"Clean Audio4: %#", audioPath);
#implementation Stub
#synthesize audioPath,
userText;
-(NSURL *)retrieveAudio:(NSURL *)cleanAudio{
self.audioPath = cleanAudio;
NSLog(#"Clean Audio1: %#", audioPath);
return cleanAudio;
}
-(NSString *)retrieveText:(NSString *)message{
self.userText = message;
NSLog(#"Text: %#", self.userText);
NSLog(#"Clean Audio2: %#", audioPath);
return message;
}
-(void)startEncrption{
NSLog(#"Clean Audio3: %#", self.audioPath);
[self encrypterWithAudioFile:self.audioPath withString:self.userText];
}
-(NSURL *)encrypterWithAudioFile:(NSURL *)audio withString:(NSString *)text{
NSLog(#"DIRTY AUDIO and TEXT: %#, %#", audio, text);
return audio;
}
-(void)dealloc{
[super dealloc];
[audioPath release];
[userText release];
}
#end
Edit: Here's the .h
#interface Stub : NSObject {
NSURL *audioPath;
NSString *userText;
}
-(NSURL *)retrieveAudio:(NSURL *)cleanAudio;
-(NSString *)retrieveText:(NSString *)message;
-(void)startEncrption;
-(NSURL *)encrypterWithAudioFile:(NSURL *)audio withString:(NSString *)text;
#property(nonatomic, retain) NSURL *audioPath;
#property(nonatomic, retain) NSString *userText;
I'm calling the methods in other classes as follows:
stubObj = [[Stub alloc] init];
[stubObj retrieveAudio:recordedTmpFile];
and
stubObj2 = [[Stub alloc] init];
[stubObj2 retrieveText:textView.text];
[stubObj2 startEncrption];
Edit: I should probably have mentioned that I have three views, all with different controllers running on a UIScrollView that are calling the [Stub] interface.
I would look into your memory management and make sure you are not over releasing that URL some where after you've passed it into this methods. What I can see from your current code is that (assuming your audioPath property is marked retain) you are actually over retaining it within this snipped when you are assigning it:
self.audioPath = [[NSURL alloc] initWithString:#"TEST"];
Should be:
self.audioPath = [NSURL urlWithString:#"TEST"];
It looks as if you are allocating the NSURL only in -[Stub getAudio:], right? It also looks like you are creating multiple Stub objects. Are you calling the getAudio: method on each of those objects before trying to use the audioPath property on that object? That could be your problem.
In your latest update of the post, you include 2 different examples of how you use this class. In the first one you have this:
stubObj = [[Stub alloc] init];
[stubObj retrieveAudio:recordedTmpFile];
I assume that this is working, and that your "Clean Audio1:" log shows the expected URL, is that correct?
In your next example you have this:
stubObj2 = [[Stub alloc] init];
[stubObj2 retrieveText:textView.text];
[stubObj2 startEncrption];
Since this is a new instance and you never call retrieveAudio on this instance, the audioPath property for this instance is never set so it is nil. When you call startEncrption it calls encrypterWithAudioFile and passes self.audioPath, which is nil. Isn't this what you are expecting or am I missing something here?
Finally figured out a fix. I ended up moving all my variables to my app delegate and referenced them from other classes by pointing to the delegate::
RonnieD1AppDelegate *appDelegate = (RonnieD1AppDelegate *)[[UIApplication sharedApplication] delegate];
I removed the startEncryption method altogether and called the method encryptWithAudioFile like this:
[stubObj2 encrypterWithAudioFile:appDelegate.audioPath withString:appDelegate.userText];
My final code ended up looking like this:
#implementation Stub
-(NSURL *)retrieveAudio:(NSURL *)cleanAudio{
RonnieD1AppDelegate *appDelegate = (RonnieD1AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.audioPath = cleanAudio;
NSLog(#"Clean Audio (retrieveAudio): %#", appDelegate.audioPath);
return cleanAudio;
}
-(NSString *)retrieveText:(NSString *)message{
// self.audioPath = [NSURL URLWithString:#"TEST"];
RonnieD1AppDelegate *appDelegate = (RonnieD1AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.userText = message;
NSLog(#"Text: %#", appDelegate.userText);
NSLog(#"Clean Audio (retireveText): %#", appDelegate.audioPath);
return message;
}
//-(void)startEncrption{
// NSLog(#"Clean Audio (startEncryption): %# TEXT: %#", self.audioPath, self.userText);
// //self.audioPath = [NSURL URLWithString:#"TEST"];
// [self encrypterWithAudioFile:self.audioPath withString:self.userText];
//
//}
-(NSURL *)encrypterWithAudioFile:(NSURL *)audio withString:(NSString *)text{
NSLog(#"DIRTY AUDIO and TEXT: %#, %#", audio, text);
return audio;
}
-(void)dealloc{
[super dealloc];
}
#end
I know there are still some memory management issues with this but its working finally so I can figured that out myself. Thanks for all your help.

Referencing superview's methods

I'm making an application in Xcode, and running into some problems. I'm using the GameKit framework to allow for bluetooth communication between two iOS devices. The application is setup so that one of the devices is the "master" and the other is the "slave," changing it's screen content based on data received from the "master" device. The user can select whether to be the master or the slave, and when that choice is made, the other device automatically becomes the opposite role. This is all done in one view controller class. When a role is chosen, a subview is added to the baseViewController.
What my problem is, is that when the subview that is added, I would like to be able to send data using the methods in the baseViewController class. With the current setup, the device invoking the action becomeMaster:sender crashes.
What I've tried so far is,
BaseViewController:
-(IBAction)becomeMaster:(id)sender {
[self dataToSend:#"slave"]; //tells peer device to become slave, since this device is master
masterViewController = [[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil];
[masterViewController setBaseViewController:self];
[self.view addSubview:masterViewController.view];
}
-(void)dataToSend:(NSString *)direction {
//—-convert an NSString object to NSData—-
NSData* data;
NSString *str = [NSString stringWithString:direction];
data = [str dataUsingEncoding: NSASCIIStringEncoding];
[self mySendDataToPeers:data];
}
-(void)dataToSend:(NSString *)direction {
//—-convert an NSString object to NSData—-
NSData* data;
NSString *str = [NSString stringWithString:direction];
data = [str dataUsingEncoding: NSASCIIStringEncoding];
[self mySendDataToPeers:data];
}
//----------------------------------------------------------------------------//
- (void)receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context {
//—-convert the NSData to NSString—-
NSString* str;
str = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
[self useReceivedData:str];
[str release];
}
-(void)useReceivedData:(NSString *)str {
if ([str isEqualToString:#"forward"]) {
[slaveViewController.view setBackgroundColor:[UIColor blackColor]];
}
}
MasterViewController:
-(void)setBaseViewController:(BaseViewController *)bvc {
baseViewController = bvc;
}
-(IBAction)goForward:(id)sender {
actionLabel.text = #"goingForward";
[baseViewController dataToSend:#"forward"];
}
Most of that code is part of the standard Apple documentation/examples, but I included it for understanding the flow of logic.
I believe the problem originates to with the becomeMaster:sender and setBaseViewController:bvc methods. Could anyone help fix? Thanks so much!
What kind of crash are you getting? EXC_BAD_ACCESS? Try turning on NSZombieEnabled in your executable's arguments. It's difficult to say what could be causing the crash, but you might try changing your setBaseViewController: implementation to this:
-(void)setBaseViewController:(BaseViewController *)bvc {
[self willChangeValueForKey:#"baseViewController"];
[baseViewController autorelease]
baseViewController = [bvc retain];
[self didChangeValueForKey:#"baseViewController"];
}
And add [baseViewController release]; to MasterViewController's -dealloc method.
Keep in mind that it's not entirely necessary to have a custom setter for baseViewController. If you have the following property declaration in your header file:
#property (nonatomic, retain) BaseViewController *baseViewController;
And you use #synthesize baseViewController, the -setBaseViewController: method is already generated for you, with key-value observing support built in. If you aren't familiar with Objective-C 2.0 properties, I suggest reading Apple's documentation.

releasing and retaining NSString* properly

Hi all i'm still new to iPhone development, but had strong experience with other programming languages. The thing that makes me pull my hair out is the Obj-C memmory management and releasing / retaining properly. I know the concept, i know "once i understand it will be easy" but i'm not quite still there, and that makes me crazy. Here i have one simple piece of code with class and method, that simply add's one character to existing string that is synthesized so used as class proprety ... the class for example is called myClass ...
myClas.h
#interface myClass : NSObject {
#private
NSString* someCommonString;
}
#propery (retain, nonatomic) NSString* someCommonString;
myClass.m
...
#synthesize someCommonString;
- (id) init
{
self = [super init];
if(self)
{
someCommonString = [[NSString alloc] initWith String:#"one "];
}
}
- (NSString*) appendString:(NSString*) stringToAdd
{
NSString* result = [someCommonString stringByAppendingString: stringToAdd];
return result;
}
- (void) doTheJob
{
NSString* test1 = #"two ";
NSString* test2 = [[NSString alloc] initWithString: #"three "];
NSString* test3 = [NSString stringWithFormat:#"four "];
self.someCommonString = [self appendString:test1];
self.someCommonString = [self appendString:test2];
self.someCommonString = [self appendString:test3];
NSLog(#"%#", someCommonString);
}
- (void) dealloc
{
[someCommonString release];
[super release];
}
...
Ok, after i alloc myClass and execute the doTheJob method, i should have #"one two three four" in the someCommonString class proprety. I know this is working, but is also leaking as hell. test1, test2 and test3 are 3 ways of initialising NSString, and only the test2 should be released, this is quite self-explanatory, but im much more worried what happens when passing them as arguments to the appendString method. Because there i know i hawe a leak, but don't know how to handle 1. stringToAdd argument [should i worry about it in appendString method at all ?] 2. the result -> if i autorelease the result, i don't know at which point the result will be deallocated. 3. sommeCommonString in appendStringMethod, should i retain it, release it or leave it alone ?
Huh :)
At a first glance, it seems to me like you're not releasing test2. After you have appended it to your common string, you do not need to retain it anymore.
self.someCommonString = [self appendString:test1];
self.someCommonString = [self appendString:test2];
self.someCommonString = [self appendString:test3];
[test2 release];
The other two (test1 and test3) are autoreleased, so your thread will reclaim them at some point).
As far as your appendString: method is concerned, result is already autoreleased and in fact you could reduce your implementation to
return [someCommonString stringByAppendingString: stringToAdd];
someCommonString is not affected by the operation at all. stringByAppendingString: returns a new autoreleased string from the concatenation of self and stringToAdd.
Hope that helps
… but im much more worried what happens when passing them as arguments to the appendString method. Because there i know i hawe a leak, but don't know how to handle
1. stringToAdd argument [should i worry about it in appendString method at all ?] …
You don't have a leak in -appendString:. You are passing stringToAdd around without retaining it and that's okay here.
The result is autoreleased and you don't have to take any action on it.
2. the result -> if i autorelease the result, i don't know at which point the result will be deallocated.
The result is already autoreleased and will be released as soon as the current NSAutoreleasePool will be released. Til then you can pass it around without retaining.
3. sommeCommonString in appendStringMethod, should i retain it, release it or leave it alone ?
Leave it alone, it's managed by the accessors. But as fedmest (and you too) said: release test2.
Well there are few problems in your code, but basic problem is you need NSMutableString string, not NSString to make your code work.
in init method, correct code to initialize is,
someCommonString = [[NSMutableString alloc] initWithString:#"one "];
You have to return the object (self) from init, otherwise it will not work, like this.
return self;
If you wanted to append the string, it should be NSMutableString, not NSString.
[[self someCommonString] appendString:test1];
[[self someCommonString] appendString:test2];
[[self someCommonString] appendString:test3];
In dealloc method, you call dealloc method of super, not release the super. So correct it it like this.
[super dealloc];
There is no need to release test1 and test3, because they are autorelease.
I have witten the correct code, try this out.
#interface myClass : NSObject {
#private
NSMutableString* someCommonString;
}
#property (retain, nonatomic) NSMutableString* someCommonString;
- (void) doTheJob;
#end
#implementation myClass
#synthesize someCommonString;
- (id) init
{
self = [super init];
if(self)
{
someCommonString = [[NSMutableString alloc] initWithString:#"one "];
}
return self;
}
- (NSString*) appendString:(NSString*) stringToAdd
{
NSString* result = [someCommonString stringByAppendingString: stringToAdd];
return result;
}
- (void) doTheJob
{
NSString* test1 = #"two ";
NSString* test2 = [[NSString alloc] initWithString: #"three "];
NSString* test3 = [NSString stringWithFormat:#"four "];
[[self someCommonString] appendString:test1];
[[self someCommonString] appendString:test2];
[[self someCommonString] appendString:test3];
NSLog(#"%#", someCommonString);
[test2 release];
}
- (void) dealloc
{
[someCommonString release];
[super dealloc];
}
#end
This is a technique which might help you deal better with what is happening with the #synthesize directive. Change your header as follows
#interface myClass : NSObject {
#private
NSString* _bob;
}
#property (retain, nonatomic) NSString* someCommonString;
and your class file to
#synthesize someCommonString = _bob;
If you recompile your code you will get build errors. Fix these and you will suddenly be able to see exactly what you are accessing via the synthesized property and what you are directly accessing.
Additionally, as already mentioned, you need to release test2 in the doTheJob method.