PDA

View Full Version : Manipulating strings in Objective-C




jsmwoolf
Nov 25, 2011, 07:04 PM
After some thought, I decided to rework in Objective-C and Cocoa in order to get the hang of OS X and possibly the iOS environment. So I decided to make a simple password encrypting program to start off(although I have worked on one application before in Objective-C and Cocoa).

In my case of encrypting, I made a program in C that simply worked based off an alogrithm that does multiplying, dividing, modulo division, and addition, if needed, using the ASCII standard(after all, you can sometimes get the value of a character by typecasting it as an integer when printing it to the console).

However, my current problem is that how do you manipulate strings within an NSString as in changing the value of the character by numbers? I know that you can't use a char variable to grab a specific character from an NSString and I don't think you can get an NSString to grab characters from a char variable. I also know that you can't use a char to grab parts from an NSTextField, so the only way to grab a string from an NSTextField is to use an NSString as far as I know.

So how could I do this?



chown33
Nov 25, 2011, 07:57 PM
However, my current problem is that how do you manipulate strings within an NSString as in changing the value of the character by numbers?

An NSString is immutable by nature. It has no methods to change its characters. The mutable subclass of NSString is NSMutableString.

NSMutableString has methods that insert, delete, or replace characters. Refer to the NSMutableString class reference doc.

NSString has methods that get characters at a specified index. See characterAtIndex: in the NSString class reference doc. Also see the related methods under the heading "Getting Characters and Bytes".

jsmwoolf
Nov 25, 2011, 08:39 PM
I also to forgot this, but can Objective-C do functions or can you only use methods?

Also, how come when you declare a method with a +(plus) you have absolutely no access to the variables of the same class? I ask this because when you declare a method with a -(minus), you can't have the class access it by code. So the only way for a class to use itself is to declare a method with a +(plus) as far as I know.

lee1210
Nov 25, 2011, 10:04 PM
I also to forgot this, but can Objective-C do functions or can you only use methods?

Also, how come when you declare a method with a +(plus) you have absolutely no access to the variables of the same class? I ask this because when you declare a method with a -(minus), you can't have the class access it by code. So the only way for a class to use itself is to declare a method with a +(plus) as far as I know.

You seem confused about class and instance variables, class and instance methods, etc. both in objective-c and in OOP in general. You should read through the objects section of the Objective-C programming guide and ask questions here if you don't understand.

http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocObjectsClasses.html#//apple_ref/doc/uid/TP30001163-CH11-SW1

Basically, + methods are class-related, often factory methods, etc. They aren't associated with an instance of the object so have no associated instance variables and effectively there are not class level variables in Objective-C, but people use static variables in their place. - methods are instance methods and are called on an instance, giving access to its instance variables. I didn't understand some of the rest of what you were saying.

As for functions... sure, have at it. All C is objective-c. You can call C functions from methods, etc.

-Lee

jsmwoolf
Nov 25, 2011, 11:00 PM
- methods are instance methods and are called on an instance, giving access to its instance variables. I didn't understand some of the rest of what you were saying. The thing is that I can't call a method within the class except for methods that have a +, not a -.

They aren't associated with an instance of the object so have no associated instance variables and effectively there are not class level variables in Objective-C, but people use static variables in their place. Oh, I know what you mean by static. I can now call it, but how come you can't use release anymore?

As for functions... sure, have at it. All C is objective-c. You can call C functions from methods, etc. How can you then make a function talk to Objective-C?

chown33
Nov 26, 2011, 12:36 AM
The thing is that I can't call a method within the class except for methods that have a +, not a -.

Because in a class method, the self variable is the class object itself. You're in the class, not in an instance of the class. If you don't understand the difference, you should study the language guide lee1210 pointed you to.


How can you then make a function talk to Objective-C?
The usual way: you write it. See a real world example (http://forums.macrumors.com/showpost.php?p=13912336).

It's obviously a function, because it's the main function. It "talks to" Objective-C, because it makes an autorelease pool, and sends several messages involving an NSMutableString.

Furthermore, it calls another function NSLog(), which also "talks to" Objective-C. It's obvious NSLog isn't a method, because it's not enclosed in [] and there's no receiver that's being sent a message.

jsmwoolf
Nov 26, 2011, 02:54 PM
The usual way: you write it. I wasn't specific there. Sorry about that.

A C function such as this:
int isPrime(int number)
{
double root = sqrt(number);
for(int x = 2; x <= root; x++)
{
if(number%x==0) //If the number does have a divisor below the root, then it's not a prime number
{
return 0;
}}
return 1;
and trying to get Objective-C to talk to it. Is it true that some things are better done or faster in C than in Objective-C?

gnasher729
Nov 26, 2011, 03:07 PM
How would you call a C function from C?
That's exactly how you would call a C function from Objective-C.

chown33
Nov 26, 2011, 03:10 PM
Please be more specific. I don't know what you mean by "talk to it".

If you mean "Can Objective-C call the C function?", then yes it can. You write it exactly the same way you would in C:
int foo = isPrime( 391 );
Since Objective-C is a superset of C, everything you write in C is also valid Objective-C. So the above line is valid C and valid Objective-C. In fact, so is your entire isPrime() function: valid C and valid Objective-C.

If you mean "Can I use Objective-C classes and methods in isPrime()?", then the answer is yes to that, too. I'm not sure why you'd do it in this function, but you could certainly use them. Your calculation involves ints, and Objective-C has the same ints as C does. So unless you're expecting something magical from Objective-C or Cocoa, I don't see why you'd stop using ints and switch to something more magical (whatever that might be). You could probably wrap the ints in NSNumber, but that would be remarkably stupid for this function. "Inappropriate use of technology" is the kinder way of putting it.

KnightWRX
Nov 26, 2011, 03:52 PM
However, my current problem is that how do you manipulate strings within an NSString as in changing the value of the character by numbers? I know that you can't use a char variable to grab a specific character from an NSString and I don't think you can get an NSString to grab characters from a char variable.

No one has pointed out this little tidbit yet. Have a look at both these methods :

+ stringWithCString:encoding:
getCString:maxLength:encoding:

These allow you to both set and get an NSString from a char * "C string" or to a char * "C String".

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html

chown33
Nov 26, 2011, 05:00 PM
No one has pointed out this little tidbit yet. Have a look at both these methods :

+ stringWithCString:encoding:
getCString:maxLength:encoding:

These allow you to both set and get an NSString from a char * "C string" or to a char * "C String".

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html

True. But if you write code that continuously goes back and forth between a C string and an NSString, you're wasting huge amounts of time (and probably memory) for no useful purpose. It's better to stick with one representation for doing all the necessary manipulations. If it's necessary to convert at the beginning or end of multiple manipulations, that's different than converting every time at every change.

subsonix
Nov 26, 2011, 05:29 PM
True. But if you write code that continuously goes back and forth between a C string and an NSString, you're wasting huge amounts of time (and probably memory) for no useful purpose. It's better to stick with one representation for doing all the necessary manipulations. If it's necessary to convert at the beginning or end of multiple manipulations, that's different than converting every time at every change.

You basically suggest the same thing in the first post, although your idea of getting a raw buffer of unicars is much better then get back to an ascii C string representation. C is definitely better suited here though, since Obj-C deals with string as an object, here we want to treat individual characters as numeric values and be able to access them directly, which suggests a simple array.

KnightWRX
Nov 26, 2011, 05:52 PM
True. But if you write code that continuously goes back and forth between a C string and an NSString, you're wasting huge amounts of time (and probably memory) for no useful purpose. It's better to stick with one representation for doing all the necessary manipulations. If it's necessary to convert at the beginning or end of multiple manipulations, that's different than converting every time at every change.

True, but if you already have a code base that relies on char * strings, it's good to know that NSString offers methods to plug into that without requiring you to rewrite huge portions of it.

Sydde
Nov 26, 2011, 11:14 PM
One approach might be to encode the string using NSArchiver and then encrypt the NSData object it returns (assuming the string is not the basis for the encryption key). This would require minimal modification of the original function, since it would receive a pointer to the data except, it would not be zero-terminated, so you would also have to have the data length to know when to stop. Then, you would decrypt the data and decode it to get the string back.

gnasher729
Nov 27, 2011, 06:03 AM
You basically suggest the same thing in the first post, although your idea of getting a raw buffer of unicars is much better then get back to an ascii C string representation. C is definitely better suited here though, since Obj-C deals with string as an object, here we want to treat individual characters as numeric values and be able to access them directly, which suggests a simple array.

Unichar has the disadvantage that it is byte-order dependent, so anything that tries to manipulate individual bytes has to be very careful. (Do you know what byte ordering the iPad uses? If you do, do you know what the byte ordering of the iPad 4 is? )

UTF8, as returned by UTF8String, is much more portable. It is also compatible with existing ASCII strings.

KnightWRX
Nov 27, 2011, 07:26 AM
(Do you know what byte ordering the iPad uses? If you do, do you know what the byte ordering of the iPad 4 is? )

The first one is easy to check and for the other one, I doubt Apple would break such compatibility with ARM being able to do either byte ordering schemes by architecture.

Kenndac
Nov 27, 2011, 08:54 AM
I wasn't specific there. Sorry about that.

A C function such as this:
int isPrime(int number)
{
double root = sqrt(number);
for(int x = 2; x <= root; x++)
{
if(number%x==0) //If the number does have a divisor below the root, then it's not a prime number
{
return 0;
}}
return 1;
and trying to get Objective-C to talk to it. Is it true that some things are better done or faster in C than in Objective-C?

Not in the way you understand it, no. The method you posted here gains no benefit from being in a C function instead of an Objective-C method declared like this:


-(BOOL)isPrime:(int)number {
...
}


A decade ago, Objective-C was used to write the audio drivers for the NeXT operating system. If Objective-C can be used to write something as performance-critical as an audio driver on decade-old hardware, it's plenty fast enough for 99% of uses today.

Premature optimisation is the enemy of good code. Write it best, then if it's too slow find ways to make it faster. Don't make assumptions before you start.

chown33
Nov 27, 2011, 09:18 AM
Not in the way you understand it, no. The method you posted here gains no benefit from being in a C function instead of an Objective-C method declared like this:


-(BOOL)isPrime:(int)number {
...
}


I disagree.

You've defined an instance method, which requires an instance (an object) to have been previously alloc'ed, init'ed, and stored somewhere accessible in order to invoke it. That's a lot of setup just to call a function. For what benefit? It behaves the same as a C function, yet you're required to do all the setup first.

A C function is not tied to an instance, and can be invoked simply by knowing its name and parameters. No setup at all.

A class method requires the class name along with the method name and parameters. That's still more information than is needed to call a C function, but at least doesn't require the setup of making an instance.

If C functions are so bad as to be avoided, then why is NSLog() a C function? Simple answer: Utility. It doesn't need to be anything more than a C function. Nothing is gained by making it a class method or an instance method. Why make things more complex than they need to be?


However, if the design goal is make a Cipher class, whose instances perform encryption or decryption for a particular algorithm, then it makes sense to use instances. One cipher state = one Cipher instance. Then, calling an isPrime method or function is likely an internal implementation detail, since not all ciphers care whether keying material is prime. And even if they did care, primality is more likely tied to a particular number representation (bignum) and the consequent arithmetic, and not tied to a specific Cipher class.

subsonix
Nov 27, 2011, 04:13 PM
Unichar has the disadvantage that it is byte-order dependent, so anything that tries to manipulate individual bytes has to be very careful. (Do you know what byte ordering the iPad uses? If you do, do you know what the byte ordering of the iPad 4 is? )

UTF8, as returned by UTF8String, is much more portable. It is also compatible with existing ASCII strings.

Yes, but allocating memory in a unichar* buffer wont get into that problem since no byte manipulations will be made. getCharacters:range: takes a unichar* buffer as an argument.