I want to convert a custom object into a propertyList. Then later I want to retrieve it via NSOutlineView. I use a NSKeyedArchiver/unArchiver to convert my object to and from a NSData.
In my custom object (OutlineItem):
-(id)pasteboardPropertyListForType:(NSPasteboardType)type
{
if ([[[info draggingPasteboard] types] containsObject: kPrivateDragUTI])
{
NSData *itemData = [NSKeyedArchiver archivedDataWithRootObject:self];
NSString* itemString = [[NSString alloc]initWithData:itemData encoding:NSASCIIStringEncoding];
return itemString;
}
In NSOutlineView:
- (id<NSPasteboardWriting>)outlineView:(NSOutlineView *)outlineView pasteboardWriterForItem:(id)item
{
OutlineItem* anItem = item;
return anItem;
}
Later:
- (BOOL)outlineView:(NSOutlineView *)destinationOutlineView
acceptDrop:(id <NSDraggingInfo>)info item:(id)destinationParentItem
childIndex:(NSInteger)destinationIndex
{
NSPasteboard *pboard = [info draggingPasteboard];
OutlineItem* pbItem = nil;
if ([[pboard types] containsObject: kPrivateDragUTI])
{
NSString* stringForData = [[info draggingPasteboard] stringForType:kPrivateDragUTI];
NSData *data = [stringForData dataUsingEncoding:NSASCIIStringEncoding];
StringForData looks OK, but data is nil at this point.
Why is data nil?
I'm downloading an NSManagedObject. Assigning an NSString to valueForKey#"username" of that object. Next, I assign that string to a cell.textLabel.text in UITableView and I'm getting an exception.
The following is the code thats throwing an exception:
-(NSString *)fetchUserName
{
if ([fetchedUserNameObject objectAtIndex:0]!= NULL)
{
recipientUser = (User*)(fetchedUserNameObject);
NSString *userName = (NSString*)[recipientUser valueForKey:#"username"];
return userName;
}
}
.....
NSString *recipientUserName = [self fetchUserName]
......
- (IBAction)reviewButtonPressed:(UIBarButtonItem *)sender
{
NSLog(#"Recipient UserName from Review Button %#", recipientUserName);
PDReviewVC *modalVC = [self.storyboard instantiateViewControllerWithIdentifier:#"pdReview"];
UINavigationController *navBar=[[UINavigationController alloc]initWithRootViewController:modalVC];
modalVC.recipientUserName= self.recipientUserName;
[self presentViewController:navBar animated:YES completion:NULL];
}
Log
2013-08-30 11:51:49.393 Time[1188:c07] Recipient UserName from Review Button (
iphone3gs
)
Now in PDReviewVC:
.h
#property (nonatomic, retain) NSString * recipientUserName;
.m
#synthesize recipientUserName;
...
//cellForRowAtIndexPath
if (indexPath.section == 0)
{
cell.textLabel.text = recipientUserName;
}
I get the following error on cell.textLabel.text = recipientUserName;:
2013-08-30 11:51:54.679 Time[1188:c07] -[__NSArrayI isEqualToString:]: unrecognized selector sent to instance 0xb889390
2013-08-30 11:53:53.303 Time[1188:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI isEqualToString:]: unrecognized selector sent to instance 0xb889390'
*** First throw call stack:
UPDATE
NSLog for the following code:
if ([fetchedUserNameObject objectAtIndex:0]!= NULL)
{
recipientUser = (User*)(fetchedUserNameObject);
NSLog(#"User %#", recipientUser);
NSString *userName = (NSString*)[recipientUser valueForKey:#"username"];
NSLog (#"userName from fetchUserName: %#", userName);
NSLog(#"%#", userName);
return userName;
}
else return NULL;
NSLog:
2013-08-30 12:36:29.495 Time[1341:c07] User (
"<User: 0xa55cd60> (entity: User; id: 0xa5a0ae0 <x-coredata://3B273CFB-1CAA-4FA0-95DC-BA9420219380-1341-000007F42366B21A/User/piphone3gs> ; data: <fault>)"
)
2013-08-30 12:36:29.496 Time[1341:c07] userName from fetchUserName: (
iphone3gs
)
2013-08-30 12:36:29.496 Time[1341:c07] (
iphone3gs
)
The answer to your question is right in your error message. :-)
It's telling you that the object you think is of type NSString is really NSArray. Thus, NSArray does not respond to any method called isEqualToString.
In your fetchUserName method you are casting an object as NSString and returning it, but apparently you are getting an NSArray here. When you set this object to your label's text property, something goes on behind the scenes to ask if the current string property is equal to the one you're trying to set. Then, error.
Try placing this line before you return in the fetchUserName method:
NSLog(#"%#",username);
return username;
Then modify your question with the console results of this NSLog() and we can help you figure out what is inside the array.
Ok, before you return the username object, do this:
NSString *username;
id object = [recipient valueForKey:#"username"];
if ([object isKindOfClass:[NSString class]]) {
username = (NSString *)object;
return username;
} else if ([object isKindOfClass:[NSArray class]]) {
NSArray *returnedArray = (NSArray *)object;
if (returnedArray.count > 0) {
id arrayMember = [returnedArray objectAtIndex:0];
if ([arrayMember isKindOfClass:[NSString class]]) {
username = (NSString *)arrayMember;
return username;
}
}
}
return nil;
You are casting [recipientUser valueForKey:#"username"] as an NSString to get your code to work, when it is in fact returning an NSArray. Remove the cast (NSString*) and get the code working so you are in fact pulling a string rather than an array from recipientUser.
To debug, I'd suggest changing your logging to:
if ([fetchedUserNameObject objectAtIndex:0]!= NULL)
{
recipientUser = (User*)(fetchedUserNameObject);
NSArray *userNames = [recipientUser valueForKey:#"username"];
for (int i=0; i < [userNames count]; i++) {
NSLog(#"Username %i is %#", i, [userNames objectAtIndex:i]);
}
}
I got issues when I analyse my code.
Espacially on this methods.
I pucked up this lines on the web. It works well but I got a Portential leak message
Potential leak on the object. (on the return).
// Encode a string to embed in an URL.
+ (NSString *)encodeToPercentEscapeString:(NSString*)string {
return (NSString *)
CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef) string,
NULL,
(CFStringRef) #"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8);
}
// Decode a percent escape encoded string.
+ (NSString *)decodeFromPercentEscapeString:(NSString *)string {
return (NSString *)
CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL,
(CFStringRef) string,
CFSTR(""),
kCFStringEncodingUTF8);
}
Thanks.
I just found this post:
iPhone memory leaking?
I have to release the CFString with CFRelease();
+ (NSString *)encodeToPercentEscapeString:(NSString*)string {
CFStringRef str = CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef) string,
NULL,
(CFStringRef) #"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8);
NSString *s = [NSString stringWithString:(NSString *)str];
CFRelease(str);
return s;
}
I need to remove spaces from the end of a string. How can I do that?
Example: if string is "Hello " it must become "Hello"
Taken from this answer here: https://stackoverflow.com/a/5691567/251012
- (NSString *)stringByTrimmingTrailingCharactersInSet:(NSCharacterSet *)characterSet {
NSRange rangeOfLastWantedCharacter = [self rangeOfCharacterFromSet:[characterSet invertedSet]
options:NSBackwardsSearch];
if (rangeOfLastWantedCharacter.location == NSNotFound) {
return #"";
}
return [self substringToIndex:rangeOfLastWantedCharacter.location+1]; // non-inclusive
}
Another solution involves creating mutable string:
//make mutable string
NSMutableString *stringToTrim = [#" i needz trim " mutableCopy];
//pass it by reference to CFStringTrimSpace
CFStringTrimWhiteSpace((__bridge CFMutableStringRef) stringToTrim);
//stringToTrim is now "i needz trim"
Here you go...
- (NSString *)removeEndSpaceFrom:(NSString *)strtoremove{
NSUInteger location = 0;
unichar charBuffer[[strtoremove length]];
[strtoremove getCharacters:charBuffer];
int i = 0;
for(i = [strtoremove length]; i >0; i--) {
NSCharacterSet* charSet = [NSCharacterSet whitespaceCharacterSet];
if(![charSet characterIsMember:charBuffer[i - 1]]) {
break;
}
}
return [strtoremove substringWithRange:NSMakeRange(location, i - location)];
}
So now just call it. Supposing you have a string that has spaces on the front and spaces on the end and you just want to remove the spaces on the end, you can call it like this:
NSString *oneTwoThree = #" TestString ";
NSString *resultString;
resultString = [self removeEndSpaceFrom:oneTwoThree];
resultString will then have no spaces at the end.
NSString *trimmedString = [string stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
//for remove whitespace and new line character
NSString *trimmedString = [string stringByTrimmingCharactersInSet:
[NSCharacterSet punctuationCharacterSet]];
//for remove characters in punctuation category
There are many other CharacterSets. Check it yourself as per your requirement.
To remove whitespace from only the beginning and end of a string in Swift:
Swift 3
string.trimmingCharacters(in: .whitespacesAndNewlines)
Previous Swift Versions
string.stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet()))
Swift version
Only trims spaces at the end of the String:
private func removingSpacesAtTheEndOfAString(var str: String) -> String {
var i: Int = countElements(str) - 1, j: Int = i
while(i >= 0 && str[advance(str.startIndex, i)] == " ") {
--i
}
return str.substringWithRange(Range<String.Index>(start: str.startIndex, end: advance(str.endIndex, -(j - i))))
}
Trims spaces on both sides of the String:
var str: String = " Yolo "
var trimmedStr: String = str.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
This will remove only the trailing characters of your choice.
func trimRight(theString: String, charSet: NSCharacterSet) -> String {
var newString = theString
while String(newString.characters.last).rangeOfCharacterFromSet(charSet) != nil {
newString = String(newString.characters.dropLast())
}
return newString
}
In Swift
To trim space & newline from both side of the String:
var url: String = "\n http://example.com/xyz.mp4 "
var trimmedUrl: String = url.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
A simple solution to only trim one end instead of both ends in Objective-C:
#implementation NSString (category)
/// trims the characters at the end
- (NSString *)stringByTrimmingSuffixCharactersInSet:(NSCharacterSet *)characterSet {
NSUInteger i = self.length;
while (i > 0 && [characterSet characterIsMember:[self characterAtIndex:i - 1]]) {
i--;
}
return [self substringToIndex:i];
}
#end
And a symmetrical utility for trimming the beginning only:
#implementation NSString (category)
/// trims the characters at the beginning
- (NSString *)stringByTrimmingPrefixCharactersInSet:(NSCharacterSet *)characterSet {
NSUInteger i = 0;
while (i < self.length && [characterSet characterIsMember:[self characterAtIndex:i]]) {
i++;
}
return [self substringFromIndex:i];
}
#end
To trim all trailing whitespace characters (I'm guessing that is actually your intent), the following is a pretty clean & concise way to do it.
Swift 5:
let trimmedString = string.replacingOccurrences(of: "\\s+$", with: "", options: .regularExpression)
Objective-C:
NSString *trimmedString = [string stringByReplacingOccurrencesOfString:#"\\s+$" withString:#"" options:NSRegularExpressionSearch range:NSMakeRange(0, string.length)];
One line, with a dash of regex.
The solution is described here: How to remove whitespace from right end of NSString?
Add the following categories to NSString:
- (NSString *)stringByTrimmingTrailingCharactersInSet:(NSCharacterSet *)characterSet {
NSRange rangeOfLastWantedCharacter = [self rangeOfCharacterFromSet:[characterSet invertedSet]
options:NSBackwardsSearch];
if (rangeOfLastWantedCharacter.location == NSNotFound) {
return #"";
}
return [self substringToIndex:rangeOfLastWantedCharacter.location+1]; // non-inclusive
}
- (NSString *)stringByTrimmingTrailingWhitespaceAndNewlineCharacters {
return [self stringByTrimmingTrailingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
And you use it as such:
[yourNSString stringByTrimmingTrailingWhitespaceAndNewlineCharacters]
I came up with this function, which basically behaves similarly to one in the answer by Alex:
-(NSString*)trimLastSpace:(NSString*)str{
int i = str.length - 1;
for (; i >= 0 && [str characterAtIndex:i] == ' '; i--);
return [str substringToIndex:i + 1];
}
whitespaceCharacterSet besides space itself includes also tab character, which in my case could not appear. So i guess a plain comparison could suffice.
let string = " Test Trimmed String "
For Removing white Space and New line use below code :-
let str_trimmed = yourString.trimmingCharacters(in: .whitespacesAndNewlines)
For Removing only Spaces from string use below code :-
let str_trimmed = yourString.trimmingCharacters(in: .whitespaces)
NSString* NSStringWithoutSpace(NSString* string)
{
return [string stringByReplacingOccurrencesOfString:#" " withString:#""];
}
Im working on an iOS app where I need to store and retrieve from an SQLite DB, a representation of a NSString that has subscripts. I can create a NSString at compile time with a constant:
#"Br\u2082_CCl\u2084"
\u2082 is a 2 subscript, \u2084 is a 4 subscript. What im storing in the SQLite db is:
"Br\u2082_CCl\u2084"
But what I can not figure out how to do, is reconvert that back into an NSString. The data comes back from the db as a char * "Br\\u2082_CCl\\u2084" Stripping out the extra slash has made no difference in my feeble experiments. I need a way get that back into an NSString - Thanks!
You need one of the NSString stringWithCString class methods or the corresponding initWithCString instance methods.
I solved the problem like this - error checking removed for clarity -
the unicode string comes into the parameter stringEncoded from the db like:
"MgBr\u2082_CH\u2082Cl\u2082"
+(NSString *)decodeUnicodeBytes:(char *)stringEncoded {
unsigned int unicodeValue;
char *p, buff[5];
NSMutableString *theString;
NSString *hexString;
NSScanner *pScanner;
theString = [[[NSMutableString alloc] init] autorelease];
p = stringEncoded;
buff[4] = 0x00;
while (*p != 0x00) {
if (*p == '\\') {
p++;
if (*p == 'u') {
memmove(buff, ++p, 4);
hexString = [NSString stringWithUTF8String:buff];
pScanner = [NSScanner scannerWithString: hexString];
[pScanner scanHexInt: &unicodeValue];
[theString appendFormat:#"%C", unicodeValue];
p += 4;
continue;
}
}
[theString appendFormat:#"%c", *p];
p++;
}
return [NSString stringWithString:theString];
}