Remove particular objects from an array based on objects from another array - iphone

Setup: Have a UITableView which shows US golf courses with name, street, state etc.
UITableView's data source is a NSMutableArray of objects from my class GolfCourse called allGolfCourses.
Now I like to remove all west coast golf courses from allGolfCourses and create a new array called eastCoastGolfCourses. I have another NSArray with string objects of all west coast states (Abbreviations) called westCoastStates but having a hard time connecting these two.
How do I iterate through allGolfCourses and remove all objects which have a state Abbreviations found in westCoastStates array?
westCoastStates Array:
self.westCoastStates = [NSMutableArray arrayWithObjects:
#"CH",
#"OR",
#"WA",
nil];
GolfCourse.h
#interface GolfCourse : NSObject
#property (nonatomic, strong) NSString *longitude;
#property (nonatomic, strong) NSString *latitude;
#property (nonatomic, strong) NSString *clubName;
#property (nonatomic, strong) NSString *state;
#property (nonatomic, strong) NSString *courseInfo;
#property (nonatomic, strong) NSString *street;
#property (nonatomic, strong) NSString *city;
#property (nonatomic, strong) NSString *clubID;
#property (nonatomic, strong) NSString *phone;
#end
Note: NSString *state; contains the state abbreviation for example: FL
I know how to do this with a single argument but don't know how to check against all strings from westCoastStates array. Hope you can help.

How about?
NSSet* westCoastStatesSet = [NSSet setWithArray:self.westCoastStates];
NSIndexSet* eastCoastGolfCoursesIndexSet = [allGolfCourses indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
GolfCourse* course = (GolfCourse*)obj;
if ([westCoastStatesSet containsObject:course.state]) {
return NO;
}
return YES;
}];
NSArray* eastCoastGolfCourses = [allGolfCourses objectsAtIndexes:eastCoastGolfCoursesIndexSet];
Update: I believe this could be condensed with the use of predicates
NSPredicate *inPredicate = [NSPredicate predicateWithFormat: #"!(state IN %#)", self.westCoastStates];
NSArray* eastCoastGolfCourses = [allGolfCourses filteredArrayUsingPredicate:inPredicate];

Pseudo-code:
for (int i = 0; i < allGolfCourses.length;) {
Course* course = [allGolfCourses objectAtIndex:i];
if (<is course in one of the "bad" states?>) {
[allGolfCourse removeObjectAtIndex:i];
}
else {
i++;
}
}

You can quickly iterate on an array like this:
[self.allGolfCourses enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
GolfCourse *currentGolfCourse = (GolfCourse *)obj;
if(![self.westCoastStates containsObject:currentGolfCourse.state]){
[self.eastCoastStates addObject:currentGolfCourse];
}
}];

Related

How do I get out data from my NSDirectory (not just a property typo)?

I'm missing something simple I think, but been at it for days now without solving this. Even Started to create a "work-around" just to solve it for now, but still want to solve this the "right" way. Any suggestions? Thank's!
.
The problem:
Seems to be missing the class Adealer (get error "-[Adealer objectAtIndex:]: unrecognized selector sent to instance 0x8c5f8b0"), but I did the import Adealer.h to this "detailsVC". But it's not just a simple error of naming the property wrong (objectForKey:#"CustName" instead of "custname" etc - tested this a lot).
Also, I've got similar "listVC"s without a class like Adealer in them, that also transfer data the same way to the same "detailsVC" and they work just fine! Then I just get the data with calls like;
self.labelRestName.text = [restDetails objectForKey:#"CustName"];
Overview:
I got a tableViewController "listVC" that creates the data and show a list, then a ViewController "detailsVC" to show the details. The data (selected row object in "listVC" is transfered via a seque and "destVC.restGPSTransfer" (NSDictionary). The data arrives ok in the "detailsVC" and looks like this in the terminal;
dealerName = Uppsala Centrum Test
dealerAdressStreet = Dragarbrunnsgatan 55
dealerAdressZip = 75320
dealerAdressCity = Uppsala
dealerLongitude = 17.63893
dealerLatitude = 59.85856
dealerDistance2 = 8586398.000000
etc
.
Following the data:
"listVC"
1) First fetching data from web via a AFNetworking json object into an NSMutableArray "restFeed" - ok.
2) Then creating my own data to an NSMutableArray within this loop into a NSMutableArray "updatedDealers" - ok;
NSMutableArray *updatedDealers = [[NSMutableArray alloc]init];
while (i+1 < [_restFeed count]) {
i++;
// Get dealer position function here
// Get distance function here
// Then create my own data here (also #imported Adealer to "listVC";
Adealer *theDealer = [[Adealer alloc]init];
theDealer.dealerName = [[_restFeed objectAtIndex:i]objectForKey:#"CustName"];
theDealer.dealerLongitude = [[_restFeed objectAtIndex:i]objectForKey:#"long"];
theDealer.dealerLatitude = [[_restFeed objectAtIndex:i]objectForKey:#"lat"];
theDealer.dealerDistance2 = theDistance;
// etc...
// Check if data ok
NSLog(#"theDealer = %#",[theDealer description]);
// Don't add dealer object without positiondata to the new array
if (![theDealer.dealerLatitude isEqualToString:#""]) {
[updatedDealers addObject:theDealer];
}
3) Then I use NSSortdescriptor to sort the dealers in NSMutableArray "updatedDealers" into distance order and finally creates the new NSMutableArray "restFeed" with this; (also did "#synthesize dealerFeed = _dealerFeed;" in "listVC") - ok.
_dealerFeed = [NSMutableArray arrayWithArray:sortedContestArray];
4) The populating some tableViewCells with this array and it works just fine - ok.;
cell.cellDealerName.text = [NSString stringWithFormat:#"%#",[[_dealerFeed objectAtIndex:indexPath.row]dealerName]];
5) In the function didSelectRowAtIndexPath transfer the selected object with the "detailsVC"'s NSDictionary "restGPSTransfer" - ok;
destVC.restGPSTransfer = [_dealerFeed objectAtIndex:myIndexPath.row];
"detailsVC":
6) The data seems to transfer ok (se top of this post) but when trying to call the data with;
self.labelRestName.text = [restGPSTransfer objectForKey:#"dealerName"];
I get this error and the app crashes: "-[Adealer objectAtIndex:]: unrecognized selector sent to instance 0x8c5f8b0".
Some more testing done...
Tried to verify the structure + it's keys and properties of the NSDictionary "restGPSTransfer", but using description only got me so far. And have not solved my problem and I still get the "unrecognized selector" error. Could it maybe have become dictionaries within dictionary's or something?
Constructed this little simple if-test to see if the property is really there. But I have to check every property "manually". There's propably a smarter way to check the hole NSDictionary / NSArray?
if ([restGPSTransfer objectForKey:#"dealerName"]) {
NSLog(#"= YES! key exists.");
} else {
NSLog(#"= Nope! key don't exists");
}
THANK'S for any help on this :-)
.
UPDATE the Adealer class files;
Adealer.h
#import <Foundation/Foundation.h>
#interface Adealer : NSObject
#property (nonatomic, retain) NSString * dealerName;
#property (nonatomic, retain) NSString * dealerAdressCity;
#property (nonatomic, retain) NSString * dealerAdressStreet;
#property (nonatomic, retain) NSString * dealerAdressZip;
#property (nonatomic, retain) NSNumber * dealerID;
#property (nonatomic, retain) NSString * dealerImages;
#property (nonatomic, retain) NSString * dealerLogo;
#property (nonatomic, retain) NSString * dealerMail;
#property (nonatomic, retain) NSString * dealerProducts;
#property (nonatomic, retain) NSString * dealerTel;
#property (nonatomic, retain) NSString * dealerText;
#property (nonatomic, retain) NSString * dealerWeb;
#property (nonatomic, retain) NSString * dealerLongitude;
#property (nonatomic, retain) NSString * dealerLatitude;
#property (nonatomic, retain) NSString *dealerDistance;
#property float dealerDistance2;
#end
Adealer.m
#import "Adealer.h"
#implementation Adealer
#synthesize dealerAdressCity, dealerAdressStreet, dealerAdressZip, dealerID, dealerImages, dealerLogo;
#synthesize dealerMail, dealerName, dealerProducts, dealerTel, dealerText, dealerWeb;
#synthesize dealerLongitude, dealerLatitude, dealerDistance,dealerDistance2;
- (NSString *)description {
// Added extension of description
NSMutableString *string = [NSMutableString string];
[string appendString:#"\ntheDealer object and it's properties:\n"];
[string appendFormat:#"dealerName = %#\n", dealerName];
[string appendFormat:#"dealerAdressStreet = %#\n", dealerAdressStreet];
[string appendFormat:#"dealerAdressZip = %#\n", dealerAdressZip];
[string appendFormat:#"dealerAdressCity = %#\n", dealerAdressCity];
[string appendFormat:#"dealerTel = %#\n", dealerTel];
[string appendFormat:#"dealerMail = %#\n", dealerMail];
[string appendFormat:#"dealerWeb = %#\n", dealerWeb];
[string appendFormat:#"dealerLogo = %#\n", dealerLogo];
[string appendFormat:#"dealerImages = %#\n", dealerImages];
[string appendFormat:#"dealerText = %#\n", dealerText];
[string appendFormat:#"dealerProducts = %#\n", dealerProducts];
[string appendFormat:#"dealerLongitude = %#\n", dealerLongitude];
[string appendFormat:#"dealerLatitude = %#\n", dealerLatitude];
[string appendFormat:#"dealerDistance = %#\n", dealerDistance];
[string appendFormat:#"dealerDistance2 = %f\n\n", dealerDistance2];
return string;
}
#end
SOLVED!
Posted if anyone else needs it here.
The solution
In my "detailsVC" I first did this iVar declaration;
.h:
Adealer *theDealer;
#property (nonatomic, retain) Adealer *theDealer;
.m:
#synthesize theDealer;
Then in my "listVC" i did this to transfer the Adealer object and it's properties to the "detailsVC" (remember that the Adealer object already has got it's properties earlier in the described "loop");
Instead of my earlier;
destVC.restGPSTransfer = [_dealerFeed objectAtIndex:myIndexPath.row];
I changed it to;
destVC.theDealer = [_dealerFeed objectAtIndex:myIndexPath.row];
And to actually show and check the transferred property in "detailsVC" I can now simply call this to get the dealers name (or any other properties);
self.labelRestName.text = theDealer.dealerName;
NSLog(#"theDealer.name = %#",theDealer.dealerName);
Works great! Happy Coding everyone!

using an NSArray in a custom class isn't working

Starting over. I am fairly new to objective C. I have created the following class and I can't figure out how to initialize the array.
Can anyone provide any guidance on how to initialize the NSArray?
StatusPost.m
#import "StatusPost.h"
#implementation StatusPost
#synthesize messageId, fromName, friendId, message, choice2, choice3, choice4, picture, fbImage, commentCount, commentArray;
-(id)initWithMessageId:(NSString*) rMessageId
fromName:(NSString*) rFromName
friendId:(NSString*) rFriendId
message:(NSString*) rMessage
choice2:(NSString*) rChoice2
choice3:(NSString*) rChoice3
choice4:(NSString*) rChoice4
picture:(NSString *) rPicture
fbImage:(UIImage *)rfbImage
commentCount:(NSString*) rCommentCount
commentArray:(NSArray*) rCommentArray
{
if (self = [super init]) {
commentArray = [NSArray new];
self.messageId = rMessageId;
self.fromName = rFromName;
self.friendId = rFriendId;
self.message = rMessage;
self.choice2 = rChoice2;
self.choice3 = rChoice3;
self.choice4 = rChoice4;
self.picture = rPicture;
self.fbImage = rfbImage;
self.commentCount = rCommentCount;
self.commentArray = rCommentArray;
}
return self;
}
- (void)dealloc {
[messageId release];
[fromName release];
[friendId release];
[message release];
[picture release];
[fbImage release];
[commentCount release];
[commentArray release];
[super dealloc];
}
#end
StatusPost.h:
#import
#interface StatusPost : NSObject {
NSString* messageId;
NSString* fromName;
NSString* friendId;
NSString* message;
NSString* choice2;
NSString* choice3;
NSString* choice4;
NSString* picture;
UIImage* fbImage;
NSString* commentCount;
NSArray* commentArray;
}
#property (nonatomic, retain) NSString* messageId;
#property (nonatomic, retain) NSString* fromName;
#property (nonatomic, retain) NSString* friendId;
#property (nonatomic, retain) NSString* message;
#property (nonatomic, retain) NSString* choice2;
#property (nonatomic, retain) NSString* choice3;
#property (nonatomic, retain) NSString* choice4;
#property (nonatomic, retain) NSString* picture;
#property (nonatomic, retain) UIImage* fbImage;
#property (nonatomic, retain) NSString* commentCount;
#property (nonatomic, retain) NSArray* commentArray;
-(id)initWithMessageId:(NSString*) rMessageId
fromName:(NSString*) rFromName
friendId:(NSString*) rFriendId
message:(NSString*) rMessage
choice2:(NSString*) rChoice2
choice3:(NSString*) rChoice3
choice4:(NSString*) rChoice4
picture:(NSString*) rPicture
fbImage:(UIImage*) rfbImage
commentCount:(NSString*) rCommentCount
commentArray:(NSArray*) rCommentArray;
#end
It is likely that you aren't ever initializing the array, so when you try to add an object, you are just sending a message to nil. In the custom class's init method, add the line:
commentArray = [NSMutableArray new];
[NSArray new] is shorthand for [[NSArray alloc] init], so, technically speaking, that statement "inits" the NSArray.
However, your code looks a bit peculiar. You have the following statements in your init:
commentArray = [NSArray new];
self.commentArray = rCommentArray;
The first statement is setting the instance variable commentArray to the address of the newly alloced/inited NSArray while the second is setting the property commentArray to a parameter value. However, you have (through the #synthesize) made the instance variable commentArray the "backing store" for the property commentArray, so when you execute the second line the effect of the first line is overwritten (and the NSArray you created is "leaked").
(But if your real question is how to "load" an NSArray with values, you should ask that question -- and you'll get different answers.)

I get a "Incorrect decrement of the reference count of an object that is not owned at this point by the caller"

When I do Analyze to find out the potential memory leak, I get a "Incorrect decrement of the reference count of an object that is not owned at this point by the caller" :
- (int)downloadUrlTofolder:(NSString *)url filename:(NSString *)name tryTime:(int)tryTime
{
int result = 0;
GetFtpService *ftpService = [[GetFtpService alloc] initwithUrlandOutPut:url output:name];
//I have delete the code here, but problem is not solved.
[ftpService release]; //the potential problem point to this line
return result;
}
Below is the "initwithUrlandOutPut" method:
- (id)initwithUrlandOutPut:(NSString *)url output:(NSString *)o
{
if(self = [super init]) {
self.urlInput = url;
self.outPath = o;
self.success = [NSString stringWithString:#"success"];
self.connected = nil;
}
return self;
}
And the interface:
#interface GetFtpService : NSObject <NSStreamDelegate>
#property (nonatomic, retain) NSInputStream *networkStream;
#property (nonatomic, copy) NSString *urlInput;
#property (nonatomic, retain) NSInputStream *fileStream;
#property (nonatomic, copy) NSString *outPath;
#property int tryTime;
#property (nonatomic, copy) NSString *success;
#property (nonatomic, copy) NSString *connected;
- (id) initwithUrlandOutPut:(NSString *)url output:(NSString *)o;
I want to know why this happened? and how to fix it?
I suspect it's because the 'w' in "initwith..." is not capitalized. Maybe the analyzer is not recognizing the method as an init method because of that.

objective c interface access

this my first interface in a.h file.
#interface EventRow : NSObject
{
NSString *title;
NSString *photo;
NSString *description;
NSMutableArray *photoArray;
}
#property (nonatomic , retain) NSString *title;
#property (nonatomic , retain) NSString *photo;
#property (nonatomic , retain) NSString *description;
#property (nonatomic , retain) NSMutableArray *photoArray;
#end
in the same file second
#interface PhotoRow : NSObject
{
//NSString *image;
NSMutableArray *imageArray;
}
#property (nonatomic , retain) NSMutableArray *imageArray;
#end
Now every object of "PhotoRow" with filled array(imageArray) stored into the "photoArray" array in EventRow's object.
Now I want to count the total elements of "imageArray" . But getting problem in access it through the EventRow's object.
any suggestions ?
Thanks..
To access the individual objects in photoArray (eventRow is an instance of EventRow
[[eventRow photoArray] objectAtIndex: someIndex]; // I don't like dot notation!
or
[eventRow.photoArray objectAtIndex: someIndex];
To access the imageArray
[[[eventRow photoArray] objectAtIndex: someIndex] imageArray];
or
[eventRow.photoArray objectAtIndex: someIndex].imageArray;
To get the count of images for that imageArray
[[[[eventRow photoArray] objectAtIndex: someIndex] imageArray] count];
or
[eventRow.photoArray objectAtIndex: someIndex].imageArray.count;
If you want to count all of the images, you need loops but you can use fast enumeration to simplifiy things
size_t total = 0;
for (PhotoRow* photoRow in [eventRow photoArray])
{
total += [[photoRow imageArray] count];
}
However, I'd like you to rethink your design a bit. Your exposure of the NSMutableArray in each class breaks encapsulation. Once a caller has got hold of the array, it can modify the internal state of a PhotoRow or an EventRow without the object knowing about it. It would be better not to have the NSMutableArray properties but to add methods to add images and photoRows directly to PhotoRows and EventRows respectively. So, for instance your photoRow class might have the following methods:
-(size_t) imageCount; // returns the result of sending -count to the internal array
-(NSImage*) imageAtIndex: (size_t) index; // returns the result of sending -objectAtIndex: to the underlying array
-(void) addImage: (NSImage*) newImage;
// etc
If I understand you correctly, your photoArray variable in your EventRow class contains PhotoRow objects. You can count the objects in the PhotoRows imageArray variable like so:
int someIndex = 0;
[((PhotoRow*)[myEventRow.photoArray objectAtIndex:someIndex]).imageArray count];

Unknown Memory Leak in iPhone

I am currently building an app for the iPhone and cannot figure out why I keep getting a memory leak to appear in the Leaks Instrument tool.
Here is the code and I have added comments to two places of where it is happening.
NSString *pathname = [[NSBundle mainBundle] pathForResource:self.toUseFile ofType:#"txt" inDirectory:#"/"];
//Line below causes a leak
self.rawCrayons = [[NSString stringWithContentsOfFile:pathname encoding:NSUTF8StringEncoding error:nil] componentsSeparatedByString:#"\n"];
self.sectionArray = [NSMutableArray array];
for (int i = 0; i < 26; i++) [self.sectionArray addObject:[NSMutableArray array]];
for(int i=0; i<self.rawCrayons.count; i++)
{
self.string = [self.rawCrayons objectAtIndex:i];
NSUInteger firstLetter = [ALPHA rangeOfString:[string substringToIndex:1]].location;
if (firstLetter != NSNotFound)
{
NSInteger audio = AUDIONUM(self.string);
NSInteger pictures = PICTURESNUM(self.string);
NSInteger videos = VIDEOSNUM(self.string);
//Line below causes a leak
[[self.sectionArray objectAtIndex:firstLetter] addObject:[[Term alloc] initToCall:NAME(self.string):audio:pictures:videos]];
}
[self.string release];
}
Thanks in advance!
Edit
Here are my property declarations.
#property (nonatomic, retain) NSArray *filteredArray;
#property (nonatomic, retain) NSMutableArray *sectionArray;
#property (nonatomic, retain) UISearchBar *searchBar;
#property (nonatomic, retain) UISearchDisplayController *searchDC;
#property (nonatomic, retain) NSString *toUseFile;
#property (nonatomic, retain) NSArray *rawCrayons;
#property (nonatomic, retain) NSString *string;
#property (nonatomic, retain) TermViewController *childController;
Here are the leaks that are occurring after follow Nick Weaver's fixes.
Here is an expanded version of one of the NSCFString.
And another image.
Image with the Responsible Caller:
Also, because this may be useful, here are the properties for Term:
#property (nonatomic, retain) NSString *name;
#property (nonatomic) NSInteger numberAudio;
#property (nonatomic) NSInteger numberPictures;
#property (nonatomic) NSInteger numberVideos;
And the implementation:
#implementation Term
#synthesize name, numberAudio, numberPictures, numberVideos;
- (Term*)initToCall:(NSString*) toSetName:(NSInteger) audio:(NSInteger) pictures:(NSInteger) videos
{
self.name = [toSetName retain];
self.numberAudio = audio;
self.numberPictures = pictures;
self.numberVideos = videos;
return self;
}
- (NSString*)getName
{
return [[name retain] autorelease];
}
-(void)dealloc
{
[name release];
[super dealloc];
}
#end
Ok, try this changed Version of Temp. I've deleted the getter because you have already one by synthesizing. You cann use the getter like this for name:
term.name
The problem was how you set the name: you want a copy of the name and setting it with the synthesized setter without calling a retain should do the trick. You could, of course, have set it with the retained property of name but you should have left out retain, like this self.name = toSetName;. The setter will retain it for you.
#property (nonatomic, copy) NSString *name;
#property (nonatomic) NSInteger numberAudio;
#property (nonatomic) NSInteger numberPictures;
#property (nonatomic) NSInteger numberVideos;
#implementation Term
#synthesize name, numberAudio, numberPictures, numberVideos;
- (Term*)initToCall:(NSString*) toSetName:(NSInteger) audio:(NSInteger) pictures:(NSInteger) videos
{
self.name = toSetName;
self.numberAudio = audio;
self.numberPictures = pictures;
self.numberVideos = videos;
return self;
}
-(void)dealloc
{
[name release];
[super dealloc];
}
Adding an object to an array will retain the instance, so the retain is 2 because you call
[[Term alloc] initToCall..
Do something like
Term *term = [[Term alloc] initToCall..];
[theArray addObject:term];
[term release];
1. See the arrow in the first line in the address column? Click it!
2. After clicking :)
Hard to tell you why the first one is leaking, because we don't know what the property is declared as. Is it retain? copy? assign? what?
The last one is fairly self explanatory though, you're taking ownership of a Term object, and not releasing it when it's added. addObject: retains its argument, meaning if you don't need that Term anymore, you need to give up ownership. I.e., pass -autorelease to the result of your initToCall:::: (which btw is a very bad name for a method)
Change:
[[self.sectionArray objectAtIndex:firstLetter] addObject:[[Term alloc] initToCall:NAME(self.string):audio:pictures:videos]];
to:
Term *tempTerm = [[Term alloc] initToCall:NAME(self.string):audio:pictures:videos];
[[self.sectionArray objectAtIndex:firstLetter] addObject:tempTerm];
[tempTerm release];
By alloc'ing an object you are responsible for it's release.