Convert NSString to few NSIntegers - xcode

I have getting data from plist to NSString, in result I see something like this "{{1848,594},{154,176}}". What is the best way to convert every single number to separate NSInteger?
NSString *frame = [myPlistKey objectForKey:#"frame"];
How to convert frame to 4 separate integers?

In this specific case, it looks like you are trying to parse the string representation of an NSRect, in which case you can just use NSRectFromString() from the Foundation framework.

Edit:
Since you are not much specific, I will try to cover your situation. If i count with the fact you have NSString *frame filled with {{1848,594},{154,176}}:
NSString *stringWithoutLeftBracket = [frame
stringByReplacingOccurrencesOfString:#"{" withString:#""];
NSString *stringWithoutRightBracket = [stringWithoutLeftBracket
stringByReplacingOccurrencesOfString:#"}" withString:#""];
NSArray *frameArray = [stringWithoutRightBracket componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#","]];
Then you can access objects with indexes like:
NSInteger integer = [[frameArray objectAtIndex:0] integerValue];
But also you could use a for loop like this:
for (NSInteger integer in frameArray) {
// Do something
}
In my opinion you have a string made from rect, means you could convert it.

Related

How to use "valueforkey"?

I'm trying to do the following - I have an Array in which some strings are stored. These strings shall be used to call an NSArray. An example will clarify what I'm trying to do:
This is the working code that I'm trying to achieve ("briefing0" is of type NSArray):
NSString *path = [docsDir stringByAppendingPathComponent:[briefing0 objectAtIndex:indexPath.row]];
This is the "same" code that I'm trying to use:
int i = 0;
NSString *path = [docsDir stringByAppendingPathComponent:[(NSArray *)[NSString stringWithFormat:#"briefing%d", i] objectAtIndex:indexPath.row]];
Any ideas?
Thanks in advance!
Tom
Assuming that briefing0 is actually a property, then yes, this is possible (and not uncommon) in ObjC via KVC.
int i = 0;
NSString *prop = [NSString stringWithFormat:#"briefing%d", i];
NSArray *array = [self valueForKey:prop];
NSString *value = [array objectAtIndex:indexPath.row];
... etc. ...
-valueForKey: is the piece you're looking for. Note that this will throw an exception if you construct a key that does not exist, and so must be used with extreme care.

Issues using NSNumberFormatter?

I'm trying to make a label to show the temperature, with a maximum of 3 digits for temperatures over a 100, but I don't want any decimals...
NSString *longtempstring = [tmp description];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:3];
[formatter setMinimumFractionDigits:0];
NSString *shorttempstring = [formatter stringForObjectValue:[NSString stringWithString:longtempstring]];
The code above always returns (null)
Any ideas?
You are getting nil because the object you are passing to stringForObjectValue: is not of the type expected.
First of all, don't use stringForObjectValue:. That is a member of the parent class, NSFormatter. NSNumberFormatter has more specific methods that avoid confusion of object types like numberFromString: and stringFromNumber:.
Second, NSNumberFormatter is used to go from number to formatted string or formatted string to number. Not directly from formatted string to formatted string. You will need to use one number formatter to read your original string and produce a number and another to produce a new shorter formatted string from that number.
Of course, you might be able to make the first step (from long string to number) easier by using NSScanner or by taking a substring of your long string (cutting out everything except for the number itself) and then using the NSString method integerValue or doubleValue. A regular expression could also be used to extract the number from the first (longer) string.
The long and short of it is, this is a two step process. The first step (getting a number) can be accomplished any number of ways and a NSNumberFormatter might not be the easiest way. The second step (getting a new shorter string) is what NSNumberFormatter is perfect for.
I fixed it by converting the NSString to an NSNumber and only pulling the integer value from the string, thus removing any decimals.
NSString *longtempstring = [tmp description];
NSNumber *tempintegervalue = [NSNumber numberWithInteger:[longtempstring integerValue]];
NSString *shorttempstring = [tempintegervalue stringValue];
NSString *longtempstring = [tmp description];
What is the value of longtempstring here? Is it even a number?
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:3];
[formatter setMinimumFractionDigits:0];
Why do you set maximum fraction digits to 3 if you say that you don't want any fraction digits? Fraction digits are what is "after the dot" and you say you don't want any decimals. If you don't want any decimals, minimum and maximum must be set to 0.
NSString *shorttempstring = [formatter stringForObjectValue:[NSString stringWithString:longtempstring]];
First of all, why are you copying the string? [NSString stringWithString:...] creates a new string that is a copy of the string you provide as argument. Strings are immutable, there is no need to copy them, they won't be modified. If you are afraid that a NSString may in fact be a NSMutableString, after all that is a subclass of NSString and you want to copy it, just copy it by calling [aString copy]. copy is a very smart method here. If the NSString is in fact a mutable string, it will really copy it, so you get an immutable copy. If it is not a mutable string, though, copy just returns the same string with a retain count increased by one (so in that case copy behaves exactly like retain). However, in your case copying makes no sense whatsoever.
And second, what makes you believe, that you can feed a string into a NSNumberFormater? It is called NSNumberFormater because it formats objects of type NSNumber. How is a NSString a NSNumber? It is not called NSStringFormater. If you feed an object of the wrong class to a formater, it will return nil, that's how this method is documented.
If your longtempstring contains a number with fraction, e.g. 12.345, then the correct code would look like this:
NSString * longtempstring = [tmp description];
NSNumberFormatter * formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:0];
[formatter setMinimumFractionDigits:0];
NSNumber * tempnumber = [NSNumber numberWithDouble:[longtempstring doubleValue]];
NSString * shorttempstring = [formatter stringForObjectValue:tempnumber];
However, if all you want to do is cut off the decimals, that is a horrible way to do it. This can be done much more effective:
double d;
NSString * longtempstring;
NSString * shorttempstring;
longtempstring = #"12.345";
d = [longtempstring doubleValue];
shorttempstring = [NSString stringWithFormat:#"%d", (int)d];
This is much shorter, needs less memory, and is at least three times faster. If you want to round the number (that means everything with a fraction .5 and above is rounded to the next higher value), just round it:
d = round([longtempstring doubleValue]);

Core Data Transformable attributes NOT working with NSPredicate

I often use Transformable for Core Data attributes, so I can change them later.
However, it seems like, if I want to use NSPredicate to find a NSManagedObject, using "uniqueKey == %#", or "uniqueKey MATCHES[cd] %#", it's not working as it should.
It always misses matching objects, until I change the attributes of the uniqueKey of the matching object to have specific class like NSString, or NSNumber.
Can someone explain the limitation of using NSPredicate with Transformable attributes?
Note: I'm not sure when/if this has changed since 5/2011 (from Scott Ahten's accepted answer), but you can absolutely search with NSPredicate on transformable attributes. Scott correctly explained why your assumptions were broken, but if Can someone explain the limitation of using NSPredicate with Transformable attributes? was your question, he implied that it is not possible, and that is incorrect.
Since the is the first google hit for "Core Data transformable value search nspredicate" (what I searched for trying to find inspiration), I wanted to add my working answer.
How to use NSPredicate with transformable properties
Short, heady answer: you need to be smart about your data transformers. You need to transfrom the value to NSData that contains what I'll call "primitive identifying information", i.e. the smallest, most identifying set of bytes that can be used to reconstruct your object. Long answer, ...
Foremost, consider:
Did you actual mean to use a transformable attribute? If any supported data type -- even binary data -- will suffice, use it.
Do you understand what transformable attributes actually are? How they pack and unpack data to and from the store? Review Non-Standard Persistent Attributes in Apple's documentation.
After reading the above, ask: does custom code that hides a supported type "backing attribute" work for you? Possibly use that technique.
Now, past those considerations, transformable attributes are rather slick. Frankly, writing an NSValueTransformer "FooToData" for Foo instances to NSData seemed cleaner than writing a lot of adhoc custom code. I haven't found a case where Core Data doesn't know it needs to transform the data using the registered NSValueTransformer.
To proceed simply address these concerns:
Did you tell Core Data what transformer to use? Open the Core Data model in table view, click the entity, click the attribute, load the Data Model Inspector pane. Under "Attribute Type: Transformable", set "Name" to your transformer.
Use a default transformer (again, see the previous Apple docs) or write your own transformer -- transformedValue: must return NSData.
NSKeyedUnarchiveFromDataTransformerName is the default transformer and may not suffice, or may draw in somewhat-transient instance data that can make two similar objects be different when they are equal.
The transformed value should contain only -- what I'll call -- "primitive identifying information". The store is going to be comparing bytes, so every byte counts.
You may also register your transformer globally. I have to do this since I actually reuse them elsewhere in the app -- e.g. NSString *name = #"FooTrans"; [NSValueTransformer setValueTransformer:[NSClassFromString(name) new] forName:name];
You probably don't want to use transforms heavily queried data operations - e.g. a large import where the primary key information uses transformers - yikes!
And then in the end, I simply use this to test for equality for high-level object attributes on models with NSPredicates -- e.g. "%K == %#" -- and it works fine. I haven't tried some of the various matching terms, but I wouldn't be surprised if they worked sometimes, and others not.
Here's an example of an NSURL to NSData transformer. Why not just store the string? Yeah, that's fine -- that's a good example of custom code masking the stored attribute. This example illustrates that an extra byte is added to the stringified URL to record if it was a file URL or not -- allowing us to know what constructors to use when the object is unpacked.
// URLToDataTransformer.h - interface
extern NSString *const kURLToDataTransformerName;
#interface URLToDataTransformer : NSValueTransformer
#end
...
// URLToDataTransformer.m - implementation
#import "URLToDataTransformer.h"
NSString *const kURLToDataTransformerName = #"URLToDataTransformer";
#implementation URLToDataTransformer
+ (Class)transformedValueClass { return [NSData class]; }
+ (BOOL)allowsReverseTransformation { return YES; }
- (id)transformedValue:(id)value
{
if (![value isKindOfClass:[NSURL class]])
{
// Log error ...
return nil;
}
NSMutableData *data;
char fileType = 0;
if ([value isFileURL])
{
fileType = 1;
data = [NSMutableData dataWithBytes:&fileType length:1];
[data appendData:[[(NSURL *)value path] dataUsingEncoding:NSUTF8StringEncoding]];
}
else
{
fileType = -1;
data = [NSMutableData dataWithBytes:&fileType length:1];
[data appendData:[[(NSURL *)value absoluteString] dataUsingEncoding:NSUTF8StringEncoding]];
}
return data;
}
- (id)reverseTransformedValue:(id)value
{
if (![value isKindOfClass:[NSData class]])
{
// Log error ...
return nil;
}
NSURL *url = nil;
NSData *data = (NSData *)value;
char fileType = 0;
NSRange range = NSMakeRange(1, [data length]-1);
[data getBytes:&fileType length:1];
if (1 == fileType)
{
NSData *actualData = [data subdataWithRange:range];
NSString *str = [[NSString alloc] initWithData:actualData encoding:NSUTF8StringEncoding];
url = [NSURL fileURLWithPath:str];
}
else if (-1 == fileType)
{
NSData *actualData = [data subdataWithRange:range];
NSString *str = [[NSString alloc] initWithData:actualData encoding:NSUTF8StringEncoding];
url = [NSURL URLWithString:str];
}
else
{
// Log error ...
return nil;
}
return url;
}
#end
Transformable attributes are usually persisted as archived binary data. As such, you are attempting to compare an instance of NSData with an instance of NSString or NSNumber.
Since these classes interpret the same data in different ways, they are not considered a match.
you can try this way
NSExpression *exprPath = [NSExpression expressionForKeyPath:#"transformable_field"];
NSExpression *exprKeyword = [NSExpression expressionForConstantValue:nsdataValue];
NSPredicate *predicate = [NSComparisonPredicate predicateWithLeftExpression:exprPath rightExpression:exprKeyword modifier:NSDirectPredicateModifier type:NSEqualToPredicateOperatorType options:0];

Search a string with nsmutablearray contents

This is probably a quick and easy question, but how would I be able to search a string with the contents of a nsmutablearray which are strings. So I have the NSString *blah = #"djfald.ji". I have the nsmutablearray filled with different extensions and I want to search the string blah to see if any of the extensions have a match. I used to use -[NSRange rangeOfString:] but that doesn't work with arrays.
Thanks,
Kevin
If you really are dealing with path extensions, it's probably better to approach this the other way round. Something like:
NSString *extension = [#"djfald.ji" pathExtension];
BOOL found = [extensions containsObject:extension];
Simply use a block:
NSUInteger extIndex = [extensionArray indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
return [blah hasSuffix:obj];
}];
NSString *extension = extensionIndex == NSNotFound ? [extensionArray objectAtIndex extIndex] : nil;
Or simply loop through the array with an enumeration.

Easy way to set a single character of an NSString to uppercase

I would like to change the first character of an NSString to uppercase. Unfortunately, - (NSString *)capitalizedString converts the first letter of every word to uppercase. Is there an easy way to convert just a single character to uppercase?
I'm currently using:
NSRange firstCharRange = NSMakeRange(0,1);
NSString* firstCharacter = [dateString substringWithRange:firstCharRange];
NSString* uppercaseFirstChar = [firstCharacter originalString];
NSMutableString* capitalisedSentence = [originalString mutableCopy];
[capitalisedSentence replaceCharactersInRange:firstCharRange withString:uppercaseFirstChar];
Which seems a little convoluted but at least makes no assumptions about the encoding of the underlying unicode string.
Very similar approach to what you have but a little more condense:
NSString *capitalisedSentence =
[dateString stringByReplacingCharactersInRange:NSMakeRange(0,1)
withString:[[dateString substringToIndex:1] capitalizedString]];
Since NSString is immutable, what you have seems to be a good way to do what you want to do. The implementations of (NSString*)uppercaseString and similar methods probably look very much like what you've written, as they return a new NSString instead of modifying the one you sent the message to.
I had a similar requirement, but it was for characters within the string. This assuming i is your index to the character you want to uppercase this worked for me:
curword = [curword stringByReplacingCharactersInRange:NSMakeRange(i,1)
withString:[[curword substringWithRange:NSMakeRange(i, 1)] capitalizedString]];
If you profile these solutions they are much slower then doing this:
NSMutableString *capitolziedString = [NSMutableString stringWithString:originalString];
NSString *firstChar = [[capitolziedString substringWithRange:NSMakeRange(0,1)] uppercaseString];
[capitolziedString replaceCharactersInRange:NSMakeRange(0, 1) withString:firstChar];
in testing on an iphone 4 running iOS 5:
#doomspork's solution ran in 0.115750 ms
while above ran in 0.064250 ms;
in testing on an Simulator running iOS 5:
#doomspork's solution ran in 0.021232 ms
while above ran in 0.007495 ms;
Aiming for maximum readability, make a category on NSString and give it this function:
NSString *capitalizeFirstLetter(NSString *string) {
NSString *firstCapital = [string substringToIndex:1].capitalizedString;
return [string stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:firstCapital];
}
Then in your code where you want it:
NSString *capitalizedSentence = capitalizeFirstLetter(dateString);
This kind of code rarely belongs in the spot where you need it and should generally be factored away into a utility class or a category to improve legibility.

Resources