objective c interface access - iphone

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];

Related

NSMutableDictionary + NSMutableArray crash

I have an NSMutableDictionary called "myScheduleFullDictionary" set up like this:
KEY VALUE
"Day 1" An NSMutableArray of NSMutableDictionaries
"Day 2" An NSMutableArray of NSMutableDictionaries
"Day 3" An NSMutableArray of NSMutableDictionaries
etc.
I'm trying to parse it - basically grab one of the MutableArrays contained as the Value of one of the Keys.
Here is my code:
// First I make a mutableCopy of the entire Dictionary:
NSMutableDictionary *copyOfMyScheduleDictionary = [myScheduleFullDictionary mutableCopy];
// Next I grab & sort all the KEYS from it:
NSArray *dayKeysArray = [[copyOfMyScheduleDictionary allKeys] sortedArrayUsingSelector:#selector(compare:)];
// I set up an NSMutableArray to hold the MutableArray I want to grab:
NSMutableArray *sessionsInThatDayArray = [[NSMutableArray alloc] init];
// Then I iterate through the KEYs and compare each to the one I'm searching for:
for (int i = 0; i < [dayKeysArray count]; i++) {
NSString *currentDayKey = [dayKeysArray objectAtIndex:i];
if ([currentDayKey isEqualToString: targetDayString]) {
NSLog(#"FOUND MATCH!!!");
// I log out the NSMutableArray I found - which works perfectly:
NSLog(#"found array is: %#", [copyOfMyScheduleDictionary objectForKey:currentDayKey]);
// But when I try to actually grab it, everything crashes:
sessionsInThatDayArray = [copyOfMyScheduleDictionary objectForKey:currentDayKey];
break;
}
}
The error I get is:
-[__NSDictionaryM name]: unrecognized selector sent to instance 0x1c5fb2d0
Not sure why its pointing out "name" as the "unrecognized selector." "name" is an NSString property of a "Session" class I declared and am working with - could that be related somehow?
Any insights?
EDIT:
Here is my "SessionObject" class definition:
#interface SessionObject : NSObject
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *speaker;
#property (nonatomic, strong) NSString *location;
#property (nonatomic, strong) NSDate *startTime, *endTime;
#property (nonatomic, strong) NSString *notes;
#property (nonatomic, strong) NSString *dayOfConference;
#end
-[__NSDictionaryM name]: unrecognized selector sent to instance 0x1c5fb2d0
This means that you are trying to call name on an NSMutableDictionary where as you should have called it on an object of class SessionObject. Check the line where you are calling something like myObject.name or [myObject name] and see if myObject is of type SessionObject and not NSMutableDictionary.
Here __NSDictionaryM denotes the NSMutableDictionary type.
I'm not sure where your bug comes from - but what are you doing there? Why don't you just write
sessionsInThatDayArray = [myScheduleFullDictionary objectForKey:targetDayString];
??? That's what NSDictionary is there for - you don't search for things by hand, you just call the method to look up the key. Instead you copied the dictionary, you extracted all the keys, you sorted the keys, you iterated through them one by one until you found it - and then you called objectForKey!!!
Apart from that, in the debugger set a breakpoint on all Objective-C exceptions. It will stop when the offending code is called, so no need to search for a needle in the haystack.

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!

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

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];
}
}];

Iphone: How to get all attributes of a class?

I have this class:
#interface Mission : BaseModel
{
NSString *Description;
NSDate *EndDate;
NSMutableArray *MissionSectionList;
NSString *Name;
NSDate *StartDate;
}
#property (nonatomic, retain) NSString *Description;
#property (nonatomic, retain) NSDate *EndDate;
#property (nonatomic, retain) NSMutableArray *MissionSectionList;
#property (nonatomic, retain) NSString *Name;
#property (nonatomic, retain) NSDate *StartDate;
#end
Is it possible to find out all the atrributes of this class?
I tried it with
Ivar class_getClassVariable(Class cls, const char* name)
But I don't know what the name should be:
name: The name of the class variable definition to obtain.
And actually I want to get all of them without knowing the name.
Is this possible?
You can use class_copyIvarList function to get the list of all instance variables of the class. Then you can iterate through it to get attributes of each ivar. (Note that you're responsible for freeing memory used for ivars array). Sample code may look like:
unsigned int count;
Ivar *varList = class_copyIvarList([Mission class],&count);
for (int i = 0; i < count; ++i){
Ivar var = varList[i];
// Do when you need with ivar
}
free(varList);

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.