Basic Objective-C syntax: "%#"? - c

I'm working through the Stanford iPhone podcasts and have some basic questions.
The first: why is there no easy string concatenation? (or am I just missing it?)
I needed help with the NSLog below, and have no idea what it's currently doing (the %# part). Do you just substitute those in wherever you need concatenation, and then comma separate the values at the end?
NSString *path = #"~";
NSString *absolutePath = [path stringByExpandingTildeInPath];
NSLog(#"My home folder is at '%#'", absolutePath);
whereas with any other programing language I'd have done it like this:
NSLog(#"My home folder is at " + absolutePath);
Thanks! (Additionally, any good guides/references for someone familiar with Java/C#/etc style syntax transitioning to Objective-C?)

%# is a placeholder in a format string, for a NSString instance.
When you do something like:
NSLog(#"My home folder is at '%#'", absolutePath);
You are telling NSLog to replace the %# placeholder with the string called absolutePath.
Likewise, if you put more placeholders, you can specify more values to replace those placeholders like this:
NSString *absolutePath = #"/home/whatever";
NSLog(#"My home #%d folder is at '%#'", 5, absolutePath);
Will print:
My home #5 is at /home/whatever
An easy way to do string concatenation:
NSString *s1 = #"Hello, ";
NSString *s2 = #"world.";
NSString *s = [NSString stringWithFormat:#"%#%#", s1, s2];
// s will be "Hello, world."
You can't have a + sign as a string concatenate operator, since there is no operator overloading in Objective-C.
Hope it helps.

That is a string format specifier. Basically it allows you to specify a placeholder in the string and the values that are to be inserted into the placeholder's spot. The link I reference above lists the different notations for the placeholders and each placeholder's specific format.
It's just like C#'s String.Format method:
NSLog(String.Format("My home folder is at '{0}'", absolutePath));

You can use NSString +stringWithFormat to do concatenation:
NSString* a = // ...
NSString* b = // ...
NSString* a_concatenated_with_b = [NSString stringWithFormat:#"%#%#",a,b];
The reason for the "%#" is that the string formatting is based off of and extends the printf format strings syntax. These functions take a variable number of arguments, and anything beginning with a percent sign (%) is interpreted as a place holder. The subsequent characters determine the type of the place holder. The standard printf does not use "%#", and since "#" is the symbol commonly used for things that Objective-C adds to the C language, it makes sense that the "#" would symbolize "an Objective-C object".
There is no automatic concatentation using the plus sign (+), because NSString* is a pointer type, and Objective-C is a strict superset of C, and so, consequently, adding to an NSString* object does pointer manipulation. Objective-C does not have any operator overloading feature as in the C++ language.

Also, %# is fairly versatile, as it actually inserts the result of the argument's description method into the result string. For NSString, that's the string's value, other classes can provide useful overrides. Similar to toString in Java, for example.

Related

Parse url query parameters in C glib?

Is it possible to get URL fragment parameters in C under glib ?
I've got a url like file://localhost/home/me/notepad.txt#line=100,2
What's the best way to get the parameters specified at the end of the url ?
There’s no single GLib function which will do what you want. If you can use libsoup (also part of the GNOME stack), then you can do it using SoupURI:
g_autoptr(SoupURI) uri = soup_uri_new (uri_string);
const gchar *fragment = soup_uri_get_fragment (uri);
That will set fragment to line=100,2. You’ll have to do further parsing of whatever your fragment format is, by hand. g_strsplit() would be useful for that.
You may also take a look on the function parse_sftp_uri from gnome-terminal terminal-nautilus.c file.
It can be easily adapted for general URIs.
Unsure if you mean to parse notepad.txt#line=100,2 or #line=100,2, nevertheless my answer should work in both cases.
You can use the strrchr() (man strrchr) function to get the last occurence of a character within a string.
Something like:
char *file;
file = strrchr(url, '/') + 1;

How do I return a string as a one element array reference in Perl?

I'm new to Perl, and this thing has got me stuck for far too long...
I want to dump a readable representation of the object itself from inside a function (I'm trying to debug something, and I'm doing this by returning an array reference which the caller expects, but containing an object dump rather than human readable text as per normal) so in my package I have:
use Data::Dumper;
sub somefunctionName{
my $self = shift;
my $d = Dumper($self);
my #retval = ();
push(#retval, $d);
return \#retval;
}
This is giving me the error "Can't use string ("the literal object dump goes here") as a HASH ref while "strict refs" in use"
I can't for the life of me figure out a way to make the error go away, no matter how I mess with the backslashes, and what I've done above looks to me like exactly what every online tutorial does... But I'm obviously missing the point somewhere.
What am I doing wrong?
According to the documentation
Dumper(LIST)
Returns the stringified form of the values in the list, subject to the configuration options below. The values will be named $VAR n in the output, where n is a numeric suffix. Will return a list of strings in a list context.
You should be able to do
#retval = Dumper($self);
return \#retval

Accessing Mac property files via C

I am accessing a plist file using the code below on a Cocoa with Objective-C application:
NSString *plistPath = [#"~/Library/Preferences/com.apple.mail.plist" stringByExpandingTildeInPath];
NSDictionary *plistData = [NSDictionary dictionaryWithContentsOfFile:plistPath];
NSArray *item = [plistData valueForKeyPath:#"MailAccounts.AccountName"];
NSLog(#"Account: %#", [item objectAtIndex:2]);
Which essentially returns the email address of the user (we also read some other information on other plist files) so we can add it to the About dialog.
I need now to read this information from the same plist files using C, not Objective-C. The files are not text, they are binary encoded plist files. Is there any way to read those property files from C?
Can I call NSDictionary etc from C? How?
Thanks for the help.
Of course you realize that Objective C is an extension of C, but in general, when I'm using plain ol' C, I use Core Foundation functions and objects instead of Objective C methods.
To your specific question: CFDictionary is toll-free bridged to NSDictionary and CFBundle to NSBundle. You can easily call CoreFoundation from plain ol' C.
You can get what you want with something like:
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFDictionaryRef dictionaryRef = CFBundleGetInfoDictionary(mainBundle);
if(dictionaryRef)
{
CFArrayRef accountsItemsArrayRef = CFDictionaryGetValue(dictionaryRef, CFSTR("MailAccounts.AccountName");
if(accountsItemsArrayRef)
{
CFStringRef accountNameRef = (CFStringRef) CFArrayGetValueAtIndex(accountsItemsArrayRef, 2);
if(accountNameRef)
{
fprintf(stderr, "Account: %s", accountName.cStr());
}
}
}
I just typed this Core Foundation translation directly into this answer box and did no error or sanity checking, which you absolutely would need to do.
Here is a slightly older tutorial that explains a bit more.
Hope this helps to get you on the right path!

How to convert cstring to NSString and NSString to cstring?

Lets say i have the following cstring
char array[1000];
How i can convert it to NSString and vice verse.
Thanks.
Apple's Developer Reference has a good article on this subject. Basically, you will do something like this:
NSString *stringFromUTFString = [[NSString alloc] initWithUTF8String:utf8String];
if the string is UTF8 encoded. Otherwise, you can use initWithCString:encoding: with which you can specify the encoding.
Here is a list of available string encodings.

One line code examples in various languages for MD5

I'm looking for one line code examples in various languages for getting a valid MD5 result (as a string, not a bytehash or what have you). For instance:
PHP:
$token = md5($var1 . $var2);
I found VB especially troublesome to do in one line.
C#:
string hash = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(input, "md5");
VB is virtually the same.
Here it is not using the System.Web namespace:
string hash = Convert.ToBase64String(new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(System.Text.Encoding.UTF8.GetBytes(input)));
Or in readable form:
string hash =
Convert.ToBase64String
(new System.Security.Cryptography.MD5CryptoServiceProvider()
.ComputeHash
(System.Text.Encoding.UTF8.GetBytes
(input)
)
);
There is a kind of universality in how this is to be accomplished. Typically, one defines a routine called md5_in_one_line (or Md5InOneLine) once, and uses it all over the place, just as one would use a library routine.
So for example, once one defines Md5InOneLine in C#, it's an easy one-liner to get the right results.
Python
token = __import__('md5').new(var1 + var2).hexdigest()
or, if md5 is alrady imported:
token = md5.new(var1 + var2).hexdigest()
Thanks to Greg Hewgill
Aren't you really just asking "what languages have std. library support for MD5?" As Justice said, in any language that supports it, it'll just be a function call storing the result in a string variable. Even without built-in support, you could write that function in any language!
Just in case you need VBScript:
download the MD5 class from webdevbros and then with one line:
hash = (new MD5).hash("some value")
Does it really matter if you can do MD5 in one line. If it's that much trouble that you can't do it in VB in 1 line, then write your own function. Then, when you need to do MD5 in VB in one line, just call that function.
If doing it all in 1 line of code is all that important, here is 1 line of VB. that doesn't use the System.Web Namespace.
Dim MD5 As New System.Security.Cryptography.MD5CryptoServiceProvider() : Dim HashBytes() As Byte : Dim MD5Str As String = "" : HashBytes = MD5.ComputeHash(System.Text.Encoding.UTF8.GetBytes("MyString")) : For i As Integer = 0 To HashBytes.Length - 1 : MD5Str &= HashBytes(i).ToString("x").PadLeft(2, "0") : Next
This will hash "MyString" and store the MD5 sum in MD5Str.
Coldfusion has a bunch of hashing algorithms, MD5 is the default.
cfset var md5hashresult = hash("string to hash")

Resources