UISearchBar, NSPredicate, w/ Array of Objects - objective-c

I have experience with Java and Android development, and am now attempting to learn Objective-C and iPhone/iPad development. In order to help teach myself, I am re-writing an application I made for android over to iPhone.
I am now attempting to use the UISearchBar in a tableview that I have populated with names from "member" objects. However, I am having trouble using NSPredicate to retrieve the name properties from inside the member objects that I have created, as it crashes. I was able to create a workaround by making an entirely seperate array filled with just the names and use that with NSPredicate, but this is far from ideal and creates problems down the road.
So basically by doing this I was able to pinpoint the problem to either how I use NSPedicate or maybe how I set my member objects in a previous class. Just to clarify, my object is properly filled when I do go into the method that uses NSPredicate so I know my objects are not just nil.
Here is my .h for my member class.
#interface AKPsiMember : NSObject
#define CURRENT_STATUS #"Current"
#define ALUMNI_STATUS #"Alumni"
#property (nonatomic, strong) NSString *firstName;
#property (nonatomic, strong) NSString *lastName;
#property (nonatomic, strong) NSString *emailAddress;
#property (nonatomic, strong) NSString *pledgeClass;
#property (nonatomic, strong) NSString *major;
#property (nonatomic, strong) NSString *phoneNum;
And also my TableViewController .m that contains the UISearchBar method delegates
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF.firstName contains[c] %#",
searchText];
self.searchedMemberNameResults = [self.listedMembers filteredArrayUsingPredicate:resultPredicate];
}
And finally the error from my stack trace
'NSInvalidArgumentException', reason: '-[AKPsiMember isEqualToString:]: unrecognized selector sent to instance 0x716bbd0'

Well I feel silly. My problem was actually setting my cell.textLabel.text = to the member object instead of the string in the object. Apparently I made this change by accident some time ago when first implementing the UISearchBar and just never noticed.
My predicate is actually working correctly now! Thanks for everyone that took the time to help me out.

Related

Realm RLMArray is nil

For some reason my RLMArray's are nil when I run my program.
I am able to see the data in the RLM browser, and it links appropriatley.
Is there something I could be missing here?
#interface HMFAlbum : RLMObject
#property NSInteger persistentId;
#property RLMArray<HMFTrack> *tracks;
#property RLMArray<HMFRange> *ranges;
#end
#interface HMFTrack : RLMObject
#property NSInteger persistentId;
#property HMFAlbum *album;
#end
RLM_ARRAY_TYPE(HMFTrack)
#interface HMFRange : RLMObject
#property NSInteger persistentId;
#property (readonly) RLMLinkingObjects *albums;
#end
RLM_ARRAY_TYPE(HMFRange)
It's expected that instance variables of persisted RLMObject instances will be nil as the property getters read values directly from the Realm file. The instance variables are only used for objects prior to being saved to the Realm, and remain nil after that point.
The Debugging section of the Realm documentation touches on this topic and mentions an LLDB script that can be used to show property values of persisted objects when debugging in Xcode. The -description method on the model classes, used by NSLog when formatting objects using the %# format specifier, will also show the property values as expected.

RLMArray properties in unmanaged RLMObjects in Objective-C

I cannot find a good example code of this anywhere....but the information I find is contradictory and confusing...
#interface DAORealmMetadata : RLMObject
#property (nonatomic, copy) NSString* id;
#end
RLM_ARRAY_TYPE(DAORealmMetadata)
#interface DAORealmBase : RLMObject
#property (nonatomic, copy) NSString* id;
#property (nonatomic, copy) RLMArray<DAORealmMetadata*><DAORealmMetadata>* metadata;
#end
RLM_ARRAY_TYPE(DAORealmBase)
Question:
Am I supposed to add #dynamic metadata in the DAORealmBase implementation...or not?
I've tried it with and without and have the same end result...a crash.
I create the unmanaged object with this code:
DAORealmBase* baseObj = [[DAORealmBase alloc] init];
DAORealmMetadata* metadataObj = [[DAORealmMetadata alloc] init];
[baseObj.metadata addObject:metadataObj];
Question:
Why does the last line cause a crash/exception?
I can only assume that I"m doing something wrong, but I cannot find any specifics as to what I did.
Thanks!
Well, I tracked the problem down, and through some trial and error, determined that the problem was the property attributes on the RLMArray properties.
Changing
#property (nonatomic, copy) RLMArray<DAORealmMetadata*><DAORealmMetadata>* metadata;
to
#property RLMArray<DAORealmMetadata*><DAORealmMetadata>* metadata;
seems to have resolved the problem. I believe specifically the 'copy' attribute.
Now, I know that the Realm docs say that the attributes are ignored and not needed, but the lint checker I'm using wants them there...and since they are "ignored", what's the harm?
Well, they are ignored on normal Realm properties, but on the RLMArray properties they aren't ignored, and problems ensue.
Hopefully this will help someone else in the future and save them some time.

Objective C Adding custom objects into NSMutableArray

I want to store a list of data records in a NSMutableArray for use in a UITableView. In other languages I would have used a simple 'type' structure to define the record structure but I understand the way to do this in Obj-C is to define a new class. I've done this as follows :
#interface CustSuppListItem : NSObject
#property (nonatomic, copy, readwrite) NSString *acCode;
#property (nonatomic, copy, readwrite) NSString *acCompany;
#property (nonatomic, copy, readwrite) NSString *acContact;
#property (nonatomic, assign, readwrite) double osBalBase;
#property (nonatomic, assign, readwrite) unsigned int acAccStatus;
#end
#implementation CustSuppListItem
#synthesize acCode, acCompany, acContact, osBalBase, acAccStatus;
#end
In the viewDidLoad of my UITableViewController I instantiate the array :
tableListDataArray = [[NSMutableArray alloc] init];
Once I have retrieved my data, I add it to the array as follows :
CustSuppListItem *custSuppItem = [[CustSuppListItem alloc] init];
[custSuppItem setAcCode:[jsonCustSuppRecord getStringForKey:#"acCode"]];
[custSuppItem setAcCompany:[jsonCustSuppRecord getStringForKey:#"acCompany"]];
[custSuppItem setAcContact:[jsonCustSuppRecord getStringForKey:#"acContact"]];
[custSuppItem setOsBalBase:[jsonCustSuppRecord getDoubleForKey:#"osBalBase"]];
[custSuppItem setAcAccStatus:[jsonCustSuppRecord getIntForKey:#"acAccStatus"]];
[tableListDataArray addObject:custSuppItem];
[custSuppItem release];
In my table cellForRowAtIndexPath method, I retrieve the data for the current cell as follows:
CustSuppListItem *listDataRecord = [tableListDataArray objectAtIndex:indexPath.row];
[cell.lblCompanyName setText:listDataRecord.acCompany]; // EXC_BAD_ACCESS here
[cell.lblAcCodeContact setText:[NSString stringWithFormat:#"%#, %#",
listDataRecord.acCode, listDataRecord.acContact]];
[cell.lblBalance setText:[Utils fmtNumber:listDataRecord.osBalBase withDecPlaces:2]];
[cell.lblStatus setText:[Utils exchAccStatusDesc:listDataRecord.acAccStatus]];
return cell;
In the dealloc method for the view controller I release the NSMutableArray :
[tableListDataArray release];
I'm very new to Obj-C so it would be great if somebody could confirm everything I've done so far makes sense and is in order. I am getting an intermittent EXC_BAD_ACCESS error when trying to read the acCompany property (see comment next to line) so something must not be right.
Any help appreciated,
Jonathan
All your code looks reasonable and correct to me at first glance.
A few things that I would look at are:
Confirm that cell definitely has a property lblCompanyName. If you're trying to assign to a property that doesn't exist then you will get this type of error. Have you defined a custom cell object type?
Confirm that it is always the acCompany property that is causing the EXC_BAD_ACCESS, and not just any property on the object. One way to do this would be to change the ordering of the lines in the cellForRowAtIndexPath method.
Confirm that the listDataRecord that's causing the crash is getting populated correctly in the first place. In other words, confirm that your jsonCustSuppRecord is always valid. What does jsonCustSuppRecord getStringForKey: return if the key doesn't exist in the jsonCustSuppRecord?
Set a breakpoint at this line: [tableListDataArray addObject:custSuppItem]; and examine the contents of the custSuppItem each time (this is an extension of point 3. above)

how to release appDelegate variables

So, for my program i am using 5 different views that all need to access and share the same data. when i first started developing for iPhone, i found a way to create and store the data in the appDelegate. now, i have a large amount of variables that i access from there.
my question now, is how do memory management of them?
appDelegate.h
#property (nonatomic, retain) NSString *analysisModeForSave;
#property (nonatomic, retain) NSString *pdfPath;
#property (nonatomic, retain) NSString *state;
#property (nonatomic, retain) NSNumber *userLevel;
#property (nonatomic, retain) NSNumber *currentHiliteID;
then #synthesize them in the .m file
and use
Agri_ImaGIS_iPhoneAppDelegate *dataCenter = (Agri_ImaGIS_iPhoneAppDelegate *) [[UIApplication sharedApplication] delegate];
to access them all in the function. right now if i don't need the variable anymore, i just set it to nil. should i release them in the appDelegate's dealloc? does the memory ever get cleared other then app termination?
Although it is true that the singleton instance of Agri_ImaGIS_iPhoneAppDelegate will not be deallocated until the app finishes it is good practice to release retain properties in the dealloc method of any class. The system would clean up after you anyway in this case but would frown at you for being messy and badly behaved...
The general rule sounds:
Whenever you alloc an object, you dealloc it in the same class.
These NSNumbers and NSStrings are no different.
You can set them to nil whereever you like but you still have to release them in the dealloc.

Program receives SIGABRT when setting an ivar

[[self numSidesBox] setName: #"numSidesBox"];
This line of code receives the SIGABRT signal and i don't know why. numSidesBox is an instance of my subclass of UITextField. I have an NSString ivar that uses the
#property (nonatomic, retain) NSString *name;
way of creating setters/getters. I have no idea what's causing this problem.
Why not try:
self.numSidesBox.name=#"numSidesbox"
This assumes you have the following in your numSidesBox header:
#property (nonatomic, retain) NSString*name;
and in your .m:
#synthesize name;
This is just a general idea to get you started and point you in the right direction; you might prefer something other than retain and will also need your numSidesBox object similarly synthesized in the current .h/.m to use dot notation on it.
Additionally, just because numSidesBox has an ivar, does not mean it actually exists in memory. Before you can use it, you have to at some point initialize it with alloc and init or a custom or dedicated initializer.