Extracting a URL from within a string - objective-c

My app receives numerous text strings which may or may not contain a URL anywhere within the string. What would be the best method to extract a URL from within a string? Thank you.

If you are working on a Mac application, Mac OS X 10.6 offers a new API to let you detect URLs with the spell checker. You may do it this way.
NSString *s = #"http://example.com"
NSInteger wordCount = 0;
NSOrthography *orthography = nil;
NSArray *checkResults = [[NSSpellChecker sharedSpellChecker] checkString:s range:NSMakeRange(0, [s length]) types:NSTextCheckingTypeLink options:nil inSpellDocumentWithTag:0 orthography:&orthography wordCount:&wordCount];
for (NSTextCheckingResult *result in checkResults) {
NSRange range = result.range;
NSURL *URL = result.URL;
}

The BSD-licensed AutoHyperlinks framework provides classes to scan text for URLs and either return them to you or mark them up as links in an attributed string.
I don't think it builds out of the box for the iPhone, but you could always add preprocessor directives to cut out any AppKit-dependent code. The scan-and-return interface should just work, once you get it to build. (Make sure to run the tests.)
Mike Abdullah wrote a patch for iPhone support. You might try that.

Related

how to get version of default browser on my mac os x

I want to get system information in mac using objective C.
I am searching a lot but did not got single line of code for
my use.They provided solutions via javascript but i want them in
objective C.
Provide me some help to go ahead.
You can use launch services to get the path to the default browser as below
LSGetApplicationForURL((CFURLRef)[NSURL URLWithString: #"http:"],
kLSRolesAll, NULL, (CFURLRef *)&appURL);
NSString *infoPlistPath = [[appURL path] stringByAppendingPathComponent:#"Contents/info.plist"];
Now read the CFBundleShortVersionString from the info.plist.
Here you go :
NSString *userName=NSUserName();
NSLog(#"UserName: %#",userName);
NSArray *ipAddress=[[NSHost currentHost] addresses];
NSLog(#"IP Address=%#",ipAddress[0]);
Updating my answer
This is tested and works well
NSWorkspace *nsSharedWorkspace = [NSWorkspace sharedWorkspace];
NSString *nsAppPath = [nsSharedWorkspace fullPathForApplication:appName];
NSBundle *nsAppBundle = [NSBundle bundleWithPath: nsAppPath];
NSDictionary *nsAppInfo = [nsAppBundle infoDictionary];
//Now you can print all dictionary to view all its contents and pick which you want
NSLog(#"%#",nsAppInfo);
//or you can get directly using following methods
NSLog(#"%#",[nsAppInfo objectForKey:#"CFBundleShortVersionString"]);
NSLog(#"%#",[nsAppInfo objectForKey:#"CFBundleVersion"]);
Dont forget to add AppKit framework

Xcode HTTP GET Request

I am making an app in which you type a value into a textbox, and the app sends an HTTP GET request to my webserver, ie www.mywebserver.server.com/ihiuahdiuehfiuseh?' + textbox variable' However, I have no idea how to work with Xcode. I am experienced in basic PHP and HTML, and advanced C++, but I am so baffled by this Xcode stuff. In all other languages I have worked with, you could look up something like "how to play a sound file in (language)", and you will get something like "oh yeah just do play(mp3url). But, with Xcode, you have to initiate the connection, initiate the variables, etc etc. I bought 2 $30 books, but I am still so confused. So, back to the point, I just need the textbox numerical number to be parsed after the ? in the URl to be parsed as a variable.
This is an example of a non-http get synchronized
You can find more
-(void)aget:(NSString *)iurl{
NSURL*url = [NSURL URLWithString:iurl];
NSURLRequest *res = [NSURLRequest requestWithURL:url];
NSOperationQueue*que=[NSOperationQueue new];
[NSURLConnection sendAsynchronousRequest:res queue:que completionHandler:^(NSURLResponse*rep,NSData*data,NSError*err){
if ([data length]> 0 && err == nil) {
NSString* rel=[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#",rel);
}else{
NSLog(#"isnull");
}
}
];
}
Through this launch him
NSString * str = [self getDataFrom: # "your url"];
     NSLog (# "% #", str);
If you have a UITextFiled, you would do the following
NSString baseUrl = #"www.mywebserver.server.com/ihiuahdiuehfiuseh?"
NSString variable = textField.text;
NSString absoluteURL = [NSString stringWithFormat:#"%#%#", baseUrl, variable];
//Send the absolute variable now to the server
If you go for a solution like Omar Abdelhafith suggests, don't forget to url-encode your 'querystring'. There is a method in the string class for this: "stringByAddingPercentEscapesUsingEncoding", but it's not perfect.
I've recently used the solution suggested here: http://simonwoodside.com/weblog/2009/4/22/how_to_really_url_encode/.

Getting AppleScript return value in Obj-C

I'm using some AppleScript in my Obj-C cocoa project to control QuickTime player (play, pause, stop, jog forward and back etc.) with great success, though my knowledge of AppleScript is very limited.
However, what I want most of all is the movie's 'Current Time' offset to convert into time-stamps for writing a subtitle script.
The following simple method shows the precise current position in (float) seconds in a dialog, but I'd really like the AppleScript to return me a variable that I can use in the rest of app. How could I modify the code below to do that? Is it even possible to access this value? Thanks a million in advance :-)
-(IBAction)currentPlayTime:(id)sender
{
NSString *scriptString=[NSString stringWithFormat:
// get time of current frame... (works perfectly)!
#"tell application \"QuickTime Player\"\n"
#"set timeScale to 600\n"
#"set curr_pos to current time of movie 1/timeScale\n"
#"display dialog curr_pos\n" // ...not in a practical form to use
#"end tell\n"];
NSDictionary *errorDict= nil;
NSAppleScript *appleScriptObject=[[NSAppleScript alloc] initWithSource:scriptString];
NSAppleEventDescriptor *eventDescriptor=[appleScriptObject executeAndReturnError: &errorDict];
// handle any errors here (snipped for brevity)
[appleScriptObject release]; // can I retain this?
}
Here's the appropriate AppleScript that you'd want to run:
property timeScale : 600
set currentPosition to missing value
tell application "QuickTime Player"
set currentPosition to (current time of document 1) / timeScale
end tell
return currentPosition
In case you're not familiar with it, property is a way to specify a global variable in AppleScript. Also, missing value is the AppleScript equivalent of nil in Objective-C. So, this script first defines a variable named currentPosition, and sets the value to missing value. It then enters the tell block which, if it succeeds, will alter the currentPosition variable. Then, outside of the tell block, it returns the currentPosition variable.
In the Objective-C code, when you create an NSAppleScript with the above code, its -executeAndReturnError: method will return the currentPosition variable in an NSAppleScriptEventDescriptor.
-(IBAction)currentPlayTime:(id)sender {
NSDictionary *error = nil;
NSMutableString *scriptText = [NSMutableString stringWithString:#"property timeScale : 600\n"];
[scriptText appendString:#"set currentPosition to missing value\n"];
[scriptText appendString:#"tell application \"QuickTime Player\"\n "];
[scriptText appendString:#"set currentPosition to (current time of document 1) / timeScale\n"];
[scriptText appendString:#"end tell\n"];
[scriptText appendString:#"return currentPosition\n"];
NSAppleScript *script = [[[NSAppleScript alloc] initWithSource:scriptText] autorelease];
NSAppleEventDescriptor *result = [script executeAndReturnError:&error];
NSLog(#"result == %#", result);
DescType descriptorType = [result descriptorType];
NSLog(#"descriptorType == %#", NSFileTypeForHFSTypeCode(descriptorType));
// returns a double
NSData *data = [result data];
double currentPosition = 0;
[data getBytes:&currentPosition length:[data length]];
NSLog(#"currentPosition == %f", currentPosition);
}
You can extract the contents of the NSAppleEventDescriptor as shown above.
Using the Scripting Bridge framework does have a slight learning curve, but would allow working with native types such as NSNumbers rather than having to go the somewhat "messier" route of extracting the raw bytes out of AppleEvent descriptor.
Use Scripting Bridge. This is a bridge between AppleScript and Objective-C, and other applications (e.g. QuickTime Player) is represented as an Objectve-C object in your code. So, you don't have to construct AppleScript code by hand.
Some say AppScript is better than Scripting Bridge.
NSAppleEventDescriptor has some methods to convert to some objective-C types, if you go to my site and download the NDScript project, it has a category of NSAppleEventDescriptor which adds a lot more methods for coercion to Objective-C type. You can use that category without the rest of the project.
http://homepage.mac.com/nathan_day/pages/source.xml

How to make QTMovie play file from URL with forced (MP3) type?

I'm using QTKit to progressively download and play an MP3 from a URL. According to this documentation, this is the code I should use to accomplish that:
NSURL *mp3URL = [NSURL URLWithString:#"http://foo.com/bar.mp3"];
NSError *error = nil;
QTMovie *sound = [[QTMovie alloc] initWithURL:mp3URL error:&error];
[sound play];
This works, and does exactly what I want — the MP3 URL is lazily downloaded and starts playing immediately. However, if the URL does not have the ".mp3" path extension, it fails:
NSURL *mp3URL = [NSURL URLWithString:#"http://foo.com/bar"];
NSError *error = nil;
QTMovie *sound = [[QTMovie alloc] initWithURL:mp3URL error:&error];
[sound play];
No error is given, no exception is raised; the duration of the sound is just set to zero, and nothing plays.
The only way I have found to work around this is to force a type by loading the data manually and using a QTDataReference:
NSURL *mp3URL = [NSURL URLWithString:#"http://foo.com/bar"];
NSData *mp3Data = [NSData dataWithContentsOfURL:mp3URL];
QTDataReference *dataReference =
[QTDataReference dataReferenceWithReferenceToData:mp3Data
name:#"bar.mp3"
MIMEType:nil];
NSError *error = nil;
QTMovie *sound = [[QTMovie alloc] initWithDataReference:dataReference error:&error];
[sound play];
However, this forces me to completely download ALL of the MP3 synchronously before I can start playing it, which is obviously undesirable. Is there any way around this?
Thanks.
Edit
Actually, it seems that the path extension has nothing to do with it; the Content-Type is simply not being set in the HTTP header. Even so, the latter code works and the former does not. Anyone know of a way to fix this, without having access to the server?
Edit 2
Anyone? I can't find information about this anywhere, and Google frustratingly now shows this page as the top result for most of my queries...
Two ideas. (The first one being a bit hacky):
To work around the missing content type, you could embed a small Cocoa webserver that supplements the missing header field and route your NSURL over that "proxy".
Some Cocoa http server implementations:
http://code.google.com/p/cocoahttpserver/
http://cocoawithlove.com/2009/07/simple-extensible-http-server-in-cocoa.html
http://culturedcode.com/cocoa/
The second one would be, to switch to a lower level framework (From QTKit to AudioToolbox).
You'd need more code, but there are some very good resources out there on how to stream mp3 using AudioToolbox.
e.g.:
http://cocoawithlove.com/2008/09/streaming-and-playing-live-mp3-stream.html
Personally I'd go with the second option. AudioToolbox isn't as straightforward as QTKit but it offers a clean solution to your problem. It's also available on both - iOS and Mac OS - so you will find plenty of information.
Update:
Did you try to use another initializer? e.g.
+ (id)movieWithAttributes:(NSDictionary *)attributes error:(NSError **)errorPtr
You can insert your URL for the key QTMovieURLAttribute and maybe you can compensate the missing content type by providing other attributes in that dictionary.
This open source project has a QTMovie category that contains methods to accomplish similar things:
http://vidnik.googlecode.com/svn-history/r63/trunk/Source/Categories/QTMovie+Async.m
If you thought weichsel's first solution was hacky, you're going to love this one:
The culprit is the Content-Type header, as you have determined. Had QTKit.framework used Objective-C internally, this would be a trivial matter of overriding -[NSHTTPURLResponse allHeaderFields] with a category of your choosing. However, QTKit.framework (for better or worse) uses Core Foundation (and Core Services) internally. These are both C-based frameworks and there is no elegant way of overriding functions in C.
That said, there is a method, just not a pretty one. Function interposition is even documented by Apple, but seems to be a bit behind the times, compared to the remainder of their documentation.
In essence, you want something along the following lines:
typedef struct interpose_s {
void *new_func;
void *orig_func;
} interpose_t;
CFStringRef myCFHTTPMessageCopyHeaderFieldValue (
CFHTTPMessageRef message,
CFStringRef headerField
);
static const interpose_t interposers[] __attribute__ ((section("__DATA, __interpose"))) = {
{ (void *)myCFHTTPMessageCopyHeaderFieldValue, (void *)CFHTTPMessageCopyHeaderFieldValue }
};
CFStringRef myCFHTTPMessageCopyHeaderFieldValue (
CFHTTPMessageRef message,
CFStringRef headerField
) {
if (CFStringCompare(headerField, CFSTR("Content-Type"), 0) == kCFCompareEqualTo) {
return CFSTR("audio/x-mpeg");
} else {
return CFHTTPMessageCopyHeaderFieldValue(message, headerField);
}
}
You might want to add logic specific to your application in terms of handling the Content-Type field lest your application break in weird and wonderful ways when every HTTP request is determined to be an audio file.
Try replacing http:// with icy://.
Just create an instance like this...
QTMovie *aPlayer = [QTMovie movieWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
fileUrl, QTMovieURLAttribute,
[NSNumber numberWithBool:YES], QTMovieOpenForPlaybackAttribute,
/*[NSNumber numberWithBool:YES], QTMovieOpenAsyncOKAttribute,*/
nil] error:error];

Objective-C: initWithContentsOfURL returning null

I'm working on an app that would display a remote html and use local images, so what I'm trying to do is download the HTML of the website and display it as a "local" page, that would have access to images in my bundle.
For some reason I can't get initWithContentsOfURL to work. I checked all manuals and examples I could find and it seems that I'm doing it correctly, but the thing just won't work, returns null all the time. The same page loaded with NSURLRequest requestWithURL works fine.
Here is the code:
- (void)awakeFromNib
{
appURL = #"http://dragontest.fantasy-fan.org";
notConnectedHTML = #"Could not connect.";
NSString *seedString = [[NSString alloc] initWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#/seed.php", appURL]]];
NSString *HTMLdata = #"";
if (seedString = #"(null)") {
NSLog(#"Can't connect on awakeFromNib.");
HTMLdata = notConnectedHTML;
}else {
HTMLdata = [NSString stringWithFormat:#"<body style='padding:0px;margin:0px;'>%#%#</body>", seedString, #"<br><img src='images/Default.png'>"];
}
[homeView loadHTMLString:HTMLdata baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] resourcePath]]];
}
Firstly, why aren't appURL and notConnectedHTML declared as NSString *? Are they declared this way elsewhere?
Secondly, you might be better off using NSURL's -urlWithString:relativeToURL: to create the actual request URL.
Thirdly (and this is your actual problem here I suspect), to compare two C primitives, you use ==. = is the assignment operator (it makes the thing on the left equal to the thing on the right). To compare two Objective-C objects, use a comparison method, like -isEqual: or -isEqualToString: (which is specifically for NSStrings).
So instead of:
if (seedString = #"(null)")
You should use
if ([seedString isEqualToString:#"(null)"])
However I suspect the reason you're trying to compare to "(null)" is because that's what NSLog spits out when an object is equal to nil. When an object is nil, the object reference itself is equal to the nil constant, so you should use this to see if an object is nil:
if (seedString == nil)
Just for good measure, some people like to use this syntax which does exactly the same thing:
if (!seedString)