NSArray objectAtIndex is not working. Please help - cocoa

NSArray* address = [NSArray arrayWithArray:[detailItem addressArray]];
NSLog(#"address = %#", address);
NSString* addressToString = #"";
int arrayCount = [address count];
for (int i = 0; i < arrayCount; i++) {
addressToString = [addressToString stringByAppendingString:[address objectAtIndex:i]];
if (i == arrayCount -1) {
addressToString = [addressToString stringByAppendingString:#""];
} else {
addressToString = [addressToString stringByAppendingString:#", "];
}
}
address is an NSArray that holds an address
2010-06-23 09:05:19.346 iPhoneExample[1093:207] address = (
{
City = "Cupertino";
Country = "United States";
CountryCode = us;
State = CA;
Street = "1 Infinite Loop";
ZIP = 95014;
}
)
I'm trying to go thru the array and create a CSV string so it would look like
Cupertino, "United States", us, CA, "1 Infinite Loop", 95014
However, I keep crashing on
addressToString = [addressToString stringByAppendingString:#", "];
Message I get is
*** -[NSCFDictionary stringByAppendingString:]: unrecognized selector sent to instance 0x1c2f10
UPDATED:
detailItem is an object of type ABContact (custom class).
ABContact has a property called addressArray
#property (nonatomic, readonly) NSArray *addressArray;
the definition of my addressArray is
- (NSArray *) addressArray {return [self arrayForProperty:kABPersonAddressProperty];}

Your "address" is an NSArray of NSDictionary, not an NSArray of NSArray.
To get the values of the dictionary as an array, you can use
[theDictionary allValues]
but there is no guarantee on the order. And I think what you actually need is:
NSMutableString* addressToString = [NSMutableString string]; // use mutable string!
for (NSDictionary* item in address) { // use fast enumeration!
[addressToString appendFormat:#"%#, \"%#\", %#, %#, \"%#\", %#\n",
[item objectForKey:#"City"],
/* etc ... */
];
}

This:
2010-06-23 09:05:19.346 iPhoneExample[1093:207] address = (
{
City = "Cupertino";
Country = "United States";
CountryCode = us;
State = CA;
Street = "1 Infinite Loop";
ZIP = 95014;
}
)
Is a NSDictionary. You will want to access its members with [dictionary objectForKey:'City']
So, your updated code should read:
NSDictionary* address = [detailItem addressArray];
NSLog(#"address = %#", address);
NSString* addressToString = #"";
int counter = 0;
for (id object in myDictionary) {
if (counter != 0)
addressToString = [addressToString stringByAppendingString:#","];
addressToString = [addressToString stringByAppendingString:object];
counter++;
}

If you could change your addressArray method to actually return an array instead of a dictionary, then you could do:
NSString * addressString = [[detailItem addressArray] componentsJoinedByString:#","];
And that's it...

Related

How to display Twitter Feed into a UITableView

I am trying to display twitter feed into a UITableView. I was able to get the feeds and NSLog the information. However, I am confused as to how to display the information instead of logging it to the console. I was told to create a custom object in order to store the desired data from the feed and then make a UITableVIew to display the information, and that is where I get stuck. Are there any suggestions or could anyone point me in the right direction? Here is how my code looks right now. I appreciate any help and thank you for your valuable time.
CODE BELOW:
#import "ViewController.h"
#import <Accounts/Accounts.h>
#import <Social/Social.h>
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[self refreshTwitter];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)refreshTwitter
{
ACAccountStore *accountStore = [[ACAccountStore alloc]init];
if (accountStore != nil)
{
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
if (accountType != nil)
{
[accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error)
{
if (granted)
{
//Succesful Access
NSArray *twitterAccounts = [accountStore accountsWithAccountType:accountType];
if (twitterAccounts != nil)
{
ACAccount *currentAccount = [twitterAccounts objectAtIndex:0];
if (currentAccount != nil)
{
NSString *requestString = #"https://api.twitter.com/1.1/statuses/user_timeline.json";
SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:[NSURL URLWithString:requestString] parameters:nil];
[request setAccount:currentAccount];
[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error)
{
if ((error == nil) && ([urlResponse statusCode] == 200))
{
NSArray *twitterFeed = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil];
NSDictionary *firstPost = [twitterFeed objectAtIndex:0];
NSLog(#"firstPost = %#", [firstPost description]);
}
}];
}
}
}
else
{
//Access Denied
}
}];
}
}
}
#end
JSON DATA:
2014-07-08 13:22:37.442 demoApp[19277:4607] firstPost = {
contributors = "<null>";
coordinates = "<null>";
"created_at" = "Wed Jul 02 18:29:43 +0000 2014";
entities = {
hashtags = (
{
indices = (
0,
20
);
text = ikercasillasoficial;
}
);
symbols = (
);
urls = (
);
"user_mentions" = (
);
};
"favorite_count" = 0;
favorited = 0;
geo = "<null>";
id = 484403559677837312;
"id_str" = 484403559677837312;
"in_reply_to_screen_name" = "<null>";
"in_reply_to_status_id" = "<null>";
"in_reply_to_status_id_str" = "<null>";
"in_reply_to_user_id" = "<null>";
"in_reply_to_user_id_str" = "<null>";
lang = es;
place = "<null>";
"retweet_count" = 0;
retweeted = 0;
source = "Twitter for iPad";
text = "#ikercasillasoficial Bien Iker. Pero fuiste muy sutil. Ojala ese hp cuando tenga hijos se le pudran en el vientre se su mujer.";
truncated = 0;
user = {
"contributors_enabled" = 0;
"created_at" = "Wed Jan 18 02:10:12 +0000 2012";
"default_profile" = 1;
"default_profile_image" = 0;
description = "Hello world";
entities = {
description = {
urls = (
);
};
};
"favourites_count" = 0;
"follow_request_sent" = 0;
"followers_count" = 2;
following = 0;
"friends_count" = 18;
"geo_enabled" = 0;
id = 467043064;
"id_str" = 467043064;
"is_translation_enabled" = 0;
"is_translator" = 0;
lang = en;
"listed_count" = 0;
location = "";
name = "Omar Devila";
notifications = 0;
"profile_background_color" = C0DEED;
"profile_background_image_url" = "http://abs.twimg.com/images/themes/theme1/bg.png";
"profile_background_image_url_https" = "https://abs.twimg.com/images/themes/theme1/bg.png";
"profile_background_tile" = 0;
"profile_image_url" = "http://pbs.twimg.com/profile_images/483760718895140864/3pLRpyzk_normal.jpeg";
"profile_image_url_https" = "https://pbs.twimg.com/profile_images/483760718895140864/3pLRpyzk_normal.jpeg";
"profile_link_color" = 0084B4;
"profile_sidebar_border_color" = C0DEED;
"profile_sidebar_fill_color" = DDEEF6;
"profile_text_color" = 333333;
"profile_use_background_image" = 1;
protected = 0;
"screen_name" = DevilaOmar;
"statuses_count" = 18;
"time_zone" = "<null>";
url = "<null>";
"utc_offset" = "<null>";
verified = 0;
};
}
Declare twitterFeed array on the class level
numberOfSectionsInTableView
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
numberOfRowsInSection
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return twitterFeed.count;
}
cellForRowAtIndexPath
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
cell.textLabel = twitterFeed[indexPath.row][#"user"][#"screen_name"];
return cell;
}

Xcode: How to find out what NSLog automatically casts into?

Hello I am trying to save and load my game data. It cannot read an integer properly from a file, however it can read a string properly though...
Strangely enough when I print the number with NSLog it works!. However if I try to use the value or pass it into another value it doesn't.
Now I could 'fix' this by converting all the numbers into strings and then saving it, then loading the strings and converting it back to numbers. However I would like to know the proper way of doing it. Also there are 1600 tiles not including other data so that would be a noticeable overhead.
Can someone tell me what I am doing wrong or what NSLog is doing automatically?
Below is the code section relevant to the question. mapData[i][j] is an array of integers representing whats on a tile.
-(void)saveGame
{
NSLog(#"%s", "Saved");
NSString *temp = [self saveFilePath];
NSLog(#"%s %#", "FilePath", temp);
NSMutableArray *values = [NSMutableArray arrayWithCapacity:1602];
int i = 0;
int j = 0;
int a = 0;
for(i = 0; i < 40; i++)
{
for(j = 0; j < 40; j++)
{
//values[i] = mapData[j][k];
[values addObject:[NSNumber numberWithInteger:mapData[i][j]]];
NSLog(#"%d, %d", i, j);
NSLog(#"%s, %d", "Map Data: ", mapData[i][j]);
NSLog(#"%#", [values objectAtIndex:a]);
a++;
}
}
// test letter OK
NSString * letterA = #"a";
[values addObject:[NSString stringWithString:letterA]];
// test independant number
NSInteger aNum = 888;
[values addObject:[NSNumber numberWithInteger:aNum]];
NSArray *value = [NSArray arrayWithArray:values];
// test conversion OK
a = 0;
for(i = 0; i < 40; i++)
{
for(j = 0; j < 40; j++)
{
NSLog(#"%#", [value objectAtIndex:a]);
a++;
}
}
NSLog(#"%#", [value objectAtIndex:a]); // letter OK
a++;
NSLog(#"%#", [value objectAtIndex:a]); // number OK
[value writeToFile:[self saveFilePath] atomically:YES]; // atomically means all or nothing. i.e power fail will not save half
}
-(NSString *)saveFilePath
{
NSArray * path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[path objectAtIndex:0] stringByAppendingPathComponent:#"savefile.plist"];
}
-(void)loadGame
{
NSLog(#"%s", "Loaded");
NSString *loadPath = [self saveFilePath];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:loadPath];
if(fileExists)
{
NSArray *values = [[NSArray alloc] initWithContentsOfFile:loadPath];
int a = 0;
for(int i = 0; i < 40; i++)
{
for(int j = 0; j < 40; j++)
{
//mapData[i][j] = [values objectAtIndex:a];
//mapData[i][j] = (NSInteger)[values objectAtIndex:a];
NSInteger * tempNumber = [values objectAtIndex:a];
NSLog(#"%#", tempNumber); // YES!
int tempInt = (int)tempNumber;
NSLog(#"%d", tempInt); // no
mapData[i][j] = tempNumber;
NSLog(#"%d, %d, %d", a , i, j);
NSLog(#"%s, %d", "Loaded Map Data: ", mapData[i][j]); // no
a++;
}
}
// string works but integer doesnt...
NSString * letter;
letter = [values objectAtIndex:a];
NSLog(#"%#", letter); // YES
// this number OK - needs pointer AND NSLog...
a++;
NSInteger * number;
number = [values objectAtIndex:a];
NSLog(#"%#", number); // YES
}
}
Nvm I figured it out. NSLog was automatically unwrapping the numbers for me. Manually unwrapping will display the correct numbers instead of memory addresses.

Iterate through array comparing dictionary values

I have a NSMutableArray *dataArray containing NSDictionaries. I want to iterate through the array in order to create a new NSMutableArray *tempDataArray with objects from the first array if the searchString matches one of the dictionaries values.
Here is my code:
self.tempDataArray = [[NSMutableArray alloc] init];
for (int i = 0; i < kDelegate.dataArray.count; i++) {
NSDictionary *dict = [kDelegate.dataArray objectAtIndex:i];
for (int j = 0; j < [dict allValues].count ; j++) {
if ([[[[dict allValues] objectAtIndex:j]stringValue] isEqualToString:searchString]) {
[self.tempDataArray addObject:dict];
}
}
}
Now this doesn't work because the dictionary also contains a NSDate. At least that is what I am reading from the error message:
-[__NSTaggedDate stringValue]: unrecognized selector sent to instance 0x41b7809e2600000d
Which I dont understand, because I do declare all the values as stringValue.
That was the first part of my problem. The second half is that this only searches for an exact match but I would rather have a search determining if the dictionaries values contain a substring.
Anyway, thanks for all your help!
(untested):
self.tempDataArray = [[NSMutableArray alloc] init];
for (NSUInteger i = 0; i < kDelegate.dataArray.count; i++) {
NSDictionary *dict = [kDelegate.dataArray objectAtIndex:i];
NSArray *allValues = [dict allValues];
for (NSUInteger j = 0; j < allValues.count; j++) {
NSObject *obj = [allValues objectAtIndex:j];
if ([obj isKindOfClass:[NSString class]]) {
NSRange range = [(NSString *)obj rangeOfString:searchString];
if (range.location != NSNotFound) {
[self.tempDataArray addObject:dict];
}
}
}
}

Objective C: Search in a tableview with NSASCIIStringEncoding

I am searching into a UITableView using this:
titles = [NSArray arrayWithArray:[datamanager titlesForEntriesBetween:(NSInteger)[slider minSelectedValue] and:(NSInteger)[slider maxSelectedValue]containing:searchText]];
How can I encode array value with NSASCIIStringEncoding during the search process?
(Array contains "tête" for example.. and when I search "tete" nothing matches.. so I will encode array value just for my search)
I would add change the third parameter to your datamanager function:
- (NSArray*)titlesForEntriesBetween:(NSInteger)startIndex
and:(NSInteger)stopIndex
withFunction:(BOOL(^)(NSString*))block {
NSMutableArray *retVal = [NSMutableArray array];
for(NSInteger i = startIndex; i <= stopIndex; ++i) {
NSString *string = [array_ objectAtIndex:i];
if (block(string)) {
[retVal insertObject:string];
}
}
return retVal;
}
And then I would call the function like this:
titles = [datamanager titlesForEntriesBetween:(NSInteger)[slider minSelectedValue] and:(NSInteger)[slider maxSelectedValue] withFunction:^(BOOL)(NSString *str) {
NSData *data = [str dataUsingEncoding:NSASCIIStringEncoding];
NSString *simpleString = [[[NSString alloc] initWithData:data usingEncoding: NSASCIIStringEncoding] autorelease];
return [simpleString isEqualToString:str];
}]];
Note: I just typed this in, I haven't tried to compile/run this.

Strip Non-Alphanumeric Characters from an NSString

I'm looking for a quick and easy way to strip non-alphanumeric characters from an NSString. Probably something using an NSCharacterSet, but I'm tired and nothing seems to return a string containing only the alphanumeric characters in a string.
We can do this by splitting and then joining. Requires OS X 10.5+ for the componentsSeparatedByCharactersInSet:
NSCharacterSet *charactersToRemove = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
NSString *strippedReplacement = [[someString componentsSeparatedByCharactersInSet:charactersToRemove] componentsJoinedByString:#""];
In Swift, the componentsJoinedByString is replaced by join(...), so here it just replaces non-alphanumeric characters with a space.
let charactersToRemove = NSCharacterSet.alphanumericCharacterSet().invertedSet
let strippedReplacement = " ".join(someString.componentsSeparatedByCharactersInSet(charactersToRemove))
For Swift2 ...
var enteredByUser = field.text .. or whatever
let unsafeChars = NSCharacterSet.alphanumericCharacterSet().invertedSet
enteredByUser = enteredByUser
.componentsSeparatedByCharactersInSet(unsafeChars)
.joinWithSeparator("")
If you want to delete just the one character, for example delete all returns...
enteredByUser = enteredByUser
.componentsSeparatedByString("\n")
.joinWithSeparator("")
What I wound up doing was creating an NSCharacterSet and the -invertedSet method that I found (it's a wonder what an extra hour of sleep does for documentation-reading abilities). Here's the code snippet, assuming that someString is the string from which you want to remove non-alphanumeric characters:
NSCharacterSet *charactersToRemove =
[[ NSCharacterSet alphanumericCharacterSet ] invertedSet ];
NSString *trimmedReplacement =
[ someString stringByTrimmingCharactersInSet:charactersToRemove ];
trimmedReplacement will then contain someString's alphanumeric characters.
Swift 3 version of accepted answer:
let unsafeChars = CharacterSet.alphanumerics.inverted
let myStrippedString = myString.components(separatedBy: unsafeChars).joined(separator: "")
Swift 5, Extension:
extension String {
/// Will strip all non alpha characters from a string
public var alpha: String {
return components(separatedBy: CharacterSet.alphanumerics.inverted).joined()
}
}
A Cleanup Category
I have a method call stringByStrippingCharactersInSet: and stringByCollapsingWhitespace that might be convenient to just drop-in.
#implementation NSString (Cleanup)
- (NSString *)clp_stringByStrippingCharactersInSet:(NSCharacterSet *)set
{
return [[self componentsSeparatedByCharactersInSet:set] componentsJoinedByString:#""];
}
- (NSString *)clp_stringByCollapsingWhitespace
{
NSArray *components = [self componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
components = [components filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"self <> ''"]];
return [components componentsJoinedByString:#" "];
}
#end
Here’s a Swift version of Cameron’s category as an extension:
extension String {
func stringByStrippingCharactersInSet(set:NSCharacterSet) -> String
{
return (self.componentsSeparatedByCharactersInSet(set) as NSArray).componentsJoinedByString("")
}
func stringByCollapsingWhitespace() -> String
{
var components:NSArray = self.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
let predicate = NSPredicate(format: "self <> ''", argumentArray: nil)
components = components.filteredArrayUsingPredicate(predicate)
return components.componentsJoinedByString(" ")
}
}
The plain cycle would be the faster execution time I think:
#implementation NSString(MyUtil)
- (NSString*) stripNonNumbers {
NSMutableString* res = [NSMutableString new];
//NSCharacterSet *numericSet = [NSCharacterSet decimalDigitCharacterSet];
for ( int i=0; i < self.length; ++i ) {
unichar c = [self characterAtIndex:i];
if ( c >= '0' && c <= '9' ) // this looks cleaner, but a bit slower: [numericSet characterIsMember:c])
[res appendFormat:#"%c", c];
}
return res;
}
#end
This is a more effective way than the provided answer
+ (NSString *)alphanumericString:(NSString *)s {
NSCharacterSet * charactersToRemove = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
NSMutableString * ms = [NSMutableString stringWithCapacity:[s length]];
for (NSInteger i = 0; i < s.length; ++i) {
unichar c = [s characterAtIndex:i];
if (![charactersToRemove characterIsMember:c]) {
[ms appendFormat:#"%c", c];
}
}
return ms;
}
or as a Category
#implementation NSString (Alphanumeric)
- (NSString *)alphanumericString {
NSCharacterSet * charactersToRemove = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
NSMutableString * ms = [NSMutableString stringWithCapacity:[self length]];
for (NSInteger i = 0; i < self.length; ++i) {
unichar c = [self characterAtIndex:i];
if (![charactersToRemove characterIsMember:c]) {
[ms appendFormat:#"%c", c];
}
}
return ms;
}
#end

Resources