Getting this error:
'NSInvalidArgumentException', reason: '-[EngineerModel _isNaturallyRTL]: unrecognized selector sent to instance
I've read How to resolve 'unrecognized selector sent to instance'? and others.
Using Xcode 4.5.1 with arc (my first time with arc)
Here's my code, which is based on an earlier non-arc project which works great
database.m
// Models for data
#import "EngineerModel.h"
- (NSArray *)returnEngineers
{
NSMutableArray *retval = [[NSMutableArray alloc] init];
NSString *query = #"SELECT * FROM engineers";
stmt = nil;
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &stmt, nil) == SQLITE_OK) {
while (sqlite3_step(stmt) == SQLITE_ROW) {
char *engineerIDChr = (char *) sqlite3_column_text(stmt, 0);
char *engineerNameChr = (char *) sqlite3_column_text(stmt, 1);
char *engineerSigFileChr = (char *) sqlite3_column_text(stmt, 2);
char *engineerPhoneChr = (char *) sqlite3_column_text(stmt, 3);
char *engineerEmailChr = (char *) sqlite3_column_text(stmt, 4);
char *engineerRegNoChr = (char *) sqlite3_column_text(stmt, 5);
NSString *engineerID = [[NSString alloc] initWithUTF8String:engineerIDChr];
NSString *engineerName = [[NSString alloc] initWithUTF8String:engineerNameChr];
NSString *engineerSigFile = [[NSString alloc] initWithUTF8String:engineerSigFileChr];
NSString *engineerPhone = [[NSString alloc] initWithUTF8String:engineerPhoneChr];
NSString *engineerEmail = [[NSString alloc] initWithUTF8String:engineerEmailChr];
NSString *engineerRegNo = [[NSString alloc] initWithUTF8String:engineerRegNoChr];
EngineerModel *info = [[EngineerModel alloc] initWithUniqueId:engineerID
engineerName:engineerName
engineerSigFile:engineerSigFile
engineerPhone:engineerPhone
engineerEmail:engineerEmail
engineerRegNo:engineerRegNo];
[retval addObject:info];
}
sqlite3_finalize(stmt);
}
return retval;
}
Database has two entries
And the model
// EngineerModel.h
#import <Foundation/Foundation.h>
#interface EngineerModel : NSObject
{
NSString *_engineerID;
NSString *_engineerName;
NSString *_engineerSigFile;
NSString *_engineerPhone;
NSString *_engineerEmail;
NSString *_engineerRegNo;
}
#property (nonatomic, copy) NSString *engineerID;
#property (nonatomic, copy) NSString *engineerName;
#property (nonatomic, copy) NSString *engineerSigFile;
#property (nonatomic, copy) NSString *engineerPhone;
#property (nonatomic, copy) NSString *engineerEmail;
#property (nonatomic, copy) NSString *engineerRegNo;
- (id)initWithUniqueId:(NSString *)AengineerID
engineerName:(NSString *)AengineerName
engineerSigFile:(NSString *)AengineerSigFile
engineerPhone:(NSString *)AengineerPhone
engineerEmail:(NSString *)AengineerEmail
engineerRegNo:(NSString *)AengineerRegNo;
- (id) init;
#end
// EngineerModel.m
#import "EngineerModel.h"
#interface EngineerModel ()
#end
#implementation EngineerModel
#synthesize engineerID, engineerName, engineerSigFile, engineerPhone, engineerEmail, engineerRegNo;
- (id)initWithUniqueId:(NSString *)AengineerID
engineerName:(NSString *)AengineerName
engineerSigFile:(NSString *)AengineerSigFile
engineerPhone:(NSString *)AengineerPhone
engineerEmail:(NSString *)AengineerEmail
engineerRegNo:(NSString *)AengineerRegNo
{
if ((self = [super init]))
{
self.engineerID = AengineerID;
self.engineerName = AengineerName;
self.engineerSigFile = AengineerSigFile;
self.engineerPhone = AengineerPhone;
self.engineerEmail = AengineerEmail;
self.engineerRegNo = AengineerRegNo;
}
return self;
}
- (id) init {
self = [super init];
return self;
}
#end
Lastly
I've added -ObjC and -all_load to other linker flags
Added #synthesize (I didn't think I had to for arc?)
If I simplify it down to
- (id)initWithId:(NSString *)AengineerID
{
NSLog(#"AengineerID %#",AengineerID);
if ((self = [super init]))
{
self.engineerID = AengineerID;
}
return self;
}
It traces AengineerID then crashes
Any ideas?
_isNaturallyRTL is a private method on NSString. So somehow you've got an EngineerModel instance where some other code is expecting an NSString.
What do you do with that array of EngineerModel objects you return from the returnEngineers method?
And just as a recommendation... using the sqlite3 C API yourself like that is a lesson in frustration. I highly recommend using something like FMDB instead.
Related
I have a picker where its values are populated from the database(using NSMutableArray), the problem is that I'm trying to add a NSString value to index 0 of my picker(or of the NSMutableArray) but nothing is showing just a blank space in that position(position 0) and below it the other values from the database are shown like this(assuming its my picker):
------------------------
------------------------
Mouse
------------------------
Keyboard
------------------------
Motherboard
------------------------
this is my code that I use to retrieve the data from the database:
-(NSMutableArray *)getProducts
{
NSMutableArray *products = [[NSMutableArray alloc] init];
Products *all = [[Products alloc]init];
NSString allstring= #"All";
all.all= allstring; // the "all" is a NSString type variable declared in Products class
[products addObject:all];
NSMutableArray *newadditions = [[NSMutableArray alloc]init];
NSMutableIndexSet *indexes =[NSMutableIndexSet indexSetWithIndex:1];
[indexes addIndex:2];
[indexes addIndex:3];
const char* sql = "SELECT ID,Name \
FROM Products";
sqlite3_stmt *statement;
int sqlResult = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
if(sqlResult == SQLITE_OK)
{
while(sqlite3_step(statement)==SQLITE_ROW)
{
int i=0;
Products *product =[[Products alloc]init];
char*name = (char*)sqlite3_column_text(statement, 1);
product.name = (name)?[NSString stringWithUTF8String:name]: #"";
[newadditions insertObject:product atIndex:i];
i++;
}
[products insertObjects:newadditions atIndexes:indexes];
sqlite3_finalize(statement);
}
else
{
NSLog(#"Problem with the database");
NSLog(#"%d",sqlResult);
}
return products;
}
Any help would be appreciated :)
EDIT:
This is my Products.h
#interface Products : NSObject
{
NSString *name;
NSString *all;
}
#property (strong,nonatomic) NSString *name;
#property (strong,nonatomic) NSString *all;
#end
Products.m:
#import "Products.h"
#implementation Products
#synthesize name;
#synthesize all;
#end
and where I call the picker:
#interface ViewController () <UIPickerViewDataSource, UIPickerViewDelegate>
#property (strong, nonatomic) IBOutlet PRLabel *namesLabel;
#property (strong, nonatomic) UIPickerView* namesPicker;
#property (strong, nonatomic) NSMutableArray *namesAll;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.namesPicker = [[UIPickerView alloc] init];
self.namesPicker.dataSource = self;
self.namesPicker.delegate = self;
self.namesPicker.showsSelectionIndicator = YES;
self.namesLabel.inputView = [self namesPicker];
self.namesLabel.inputAccessoryView = [self accessoryToolbar];
DBAccess *dbAccess = [[DBAccess alloc]init];
self.namesAll = [dbAccess getProducts];
[dbAccess closeDatabase];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - UIPickerViewDataSource
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
return [self.namesAll count];
}
#pragma mark - UIPickerViewDelegate
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
Products * prod = [self.namesAll objectAtIndex:row];
return prod.type;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
self.namesLabel.text = [self.namesPicker.delegate pickerView:pickerView titleForRow:row forComponent:component];
}
#end
EDIT AGAIN:
the getProducts before I try to add "All" string to first position of array:
-(NSMutableArray *)getProducts
{
NSMutableArray *products = [[NSMutableArray alloc] init];
const char* sql = "SELECT ID,Name \
FROM Products ";
sqlite3_stmt *statement;
int sqlResult = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
if(sqlResult == SQLITE_OK)
{
while(sqlite3_step(statement)==SQLITE_ROW)
{
Product *product =[[Product alloc]init];
char*name = (char*)sqlite3_column_text(statement, 1);
product.name = (name)?[NSString stringWithUTF8String:name]: #"";
[products addObject:product];
}
NSLog(#"%#",products);
sqlite3_finalize(statement);
}
else
{
NSLog(#"Problem with the database");
NSLog(#"%d",sqlResult);
}
return products;
}
LOG:
2013-07-24 13:49:56.425 just[1401:c07] Opening Database
2013-07-24 13:49:56.433 just[1401:c07] (
All,
"<Product: 0x719f350>",
"<Product: 0x719fcb0>",
"<Product: 0x719ff30>"
)
2013-07-24 13:49:58.053 just[1401:c07] -[__NSCFConstantString name]: unrecognized selector sent to instance 0xd938
2013-07-24 13:49:58.054 just[1401:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFConstantString name]: unrecognized selector sent to instance 0xd938'
*** First throw call stack:
(0x20a1012 0x11aee7e 0x212c4bd 0x2090bbc 0x209094e 0x6a06 0xeb6fc 0xee886 0x1ad8fb 0x1ad9cf 0x1961bb 0x194872 0x19f5d4 0x52e299 0xed27a 0xed10c 0x1432dd 0x11c26b0 0x269dfc0 0x269233c 0x269deaf 0x4a23fe 0x49b798 0x49ca34 0x49e8a2 0x49e931 0x49e97b 0x498117 0x201386 0x200e29 0x2935 0x125cef 0x125f02 0x103d4a 0xf5698 0x1ffcdf9 0x1ffcad0 0x2016bf5 0x2016962 0x2047bb6 0x2046f44 0x2046e1b 0x1ffb7e3 0x1ffb668 0xf2ffc 0x250d 0x2435)
libc++abi.dylib: terminate called throwing an exception
(lldb)
Change all.all to all.name, and t should work.
As a comment, your code is not very readable. The naming of variables is confusing and the use of indexes is scary. There's no need for a newadditions collection if you can do addObject: for each record you read.
The picker cannot show a random object, but a only a string (in its base configuration). Make sure you add the name or some other string attribute of your Products class to the array, (or instruct your picker's datasource to use the right field).
You should really change some names of your classes and variables. If one instance of your class represents a product, the class name should be Product not Products. Also, to use a property name like all is really not intuitive - try to think of something more generic and descriptive.
Also, in your for loop you set i to 0, use it once and then increase it at the end of the loop. Why? Your index set code can also be eliminated.
suitsArray is MutableArray with objects (words) added when buttons are in selected state.
In the following piece, I need to make suitsCriteriaString a clean string with only a space separating the words from suitsArray, meaning no comma or other symbols! (with NSSet or something?)
NSString *suitsCriteriaString = [NSString stringWithFormat:#"%#", suitsArray];
NSString *wineSuitsString = [wine objectForKey:#"Suits"];
NSRange range = [wineSuitsString rangeOfString:suitsCriteriaString options:NSCaseInsensitiveSearch];
Then, the NSRange, if it's done right, should check if the words in suitsCriteriaString, are existing in wineSuitsString. Then, the results should be filtered to containing only the matching words!
Codes for my search function follows, let me know if you need some more info to make this work.
SearchViewController.h
#import <UIKit/UIKit.h>
#interface SearchViewController : UIViewController {
#property (nonatomic, strong) NSMutableArray *allObjectsArray;
#property (nonatomic, strong) NSMutableArray *resultObjectsArray;
#property (nonatomic, strong) NSMutableArray *suitsArray;
#property (nonatomic, retain) IBOutlet UISlider *minPrisSlider;
#property (nonatomic, retain) IBOutlet UISlider *maxPrisSlider;
-(IBAction)searchButtonPressed:(id)sender;
#end
SearchViewController.m:
Fill allObjectsArray:
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Wine.plist"];
allObjectsArray = [[NSMutableArray alloc] initWithContentsOfFile:path];
}
Add or remove object from suitsArray, I have 10 buttons similar to this:
-(IBAction)lambButtonPressed:(id)sender
{
if (lambButtonSelected == 0) {
lambButtonSelected = 1;
[suitsArray addObject:#"lamb"];
} else {
lambButtonSelected = 0;
[suitsArray removeObject:#"lamb"];
}
}
Then, add objects to search results:
-(IBAction)searchButtonPressed:(id)sender{
resultObjectsArray = [NSMutableArray array];
for(NSDictionary *wine in allObjectsArray)
{
//String for price
NSString *winePrice = [wine objectForKey:#"Price"];
/*THIS IS WHERE I'M TRYING TO CHECK IF THE WORDS IN suitsCriteriaString
ARE EXISTING IN wineSuitsString */
NSString *suitsCriteriaString = [NSString stringWithFormat:#"%#", suitsArray];
NSString *wineSuitsString = [wine objectForKey:#"Suits"];
NSRange range = [wineSuitsString rangeOfString:suitsCriteriaString options:NSCaseInsensitiveSearch];
//THEN LAST, ADD OBJECTS WITH MATCH OF PRICE CRITERIA AND SUITS CRITERIA TO RESULTS:
BOOL priceConditionGood = YES;
if (minPrisSlider.value <= maxPrisSlider.value && (winePrice.floatValue < minPrisSlider.value || winePrice.floatValue > maxPrisSlider.value))
priceConditionGood = NO;
if (range.location != NSNotFound && priceConditionGood)
[resultObjectsArray addObject:wine];
}
}
//AND PUSH RESULTS CONTROLLER:
ResultsTableViewController *nextController = [[self storyboard] instantiateViewControllerWithIdentifier:#"ResultsController"];
nextController.objectsArray = [[NSMutableArray alloc]initWithArray:resultObjectsArray];
[self.navigationController pushViewController:nextController animated:YES];
}
"suitsCriteriaString" is not going to give you what you want. It's going to be a whole lot easier to just iterate over "suitsArray" and compare each word:
NSString *wineSuitsString = [wine objectForKey:#"Suits"];
BOOL foundMatch = true;
for (NSString *suit in suitsArray) {
NSRange range = [wineSuitsString rangeOfString:suit options:NSCaseInsensitiveSearch];
if (range.location == NSNotFound) {
foundMatch = false;
break;
}
}
You can do that using the componentsJoinedByString: method like that:
NSString *suitsCriteriaString = [suitsArray componentsJoinedByString:#" "];
NSString *wineSuitsString = [wine objectForKey:#"Suits"];
NSRange range = [wineSuitsString rangeOfString:suitsCriteriaString options:NSCaseInsensitiveSearch];
Hi, I am trying to get array from StudentDbwithsearchbarViewController class to SearchBarDB class but resultant array not having any data it is giving null Array. Please help me out with this.
thanks in advance
#import <UIKit/UIKit.h>
#interface StudentDbwithsearchbarViewController : UIViewController<UITableViewDelegate,UITableViewDataSource> {
IBOutlet UITextField *txtMarks,*txtSname;
IBOutlet UITableView *tableStudents;
NSMutableArray *arrStudents;
}
#property(nonatomic,retain) NSMutableArray *arrStudents;
-(IBAction)saveStudentDetails;
-(IBAction)gotoSearchpage;
#end
#implementation StudentDbwithsearchbarViewController
#synthesize arrStudents;
- (void)viewDidLoad {
[super viewDidLoad];
arrStudents = [[DbStudent getStudentRecords]retain];
NSLog(#"%#",arrStudents);
NSLog(#"%d",[arrStudents retainCount]);
}
#import "DbStudent.h"
+(NSMutableArray*)getStudentRecords{
NSArray *arrDocPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *strDestPath = [NSString stringWithFormat:#"%#/Student5.sqlite",[arrDocPath objectAtIndex:0]];
NSMutableArray *arrStudents = [[NSMutableArray alloc]init];
sqlite3 *db;
if(sqlite3_open([strDestPath UTF8String], &db)==SQLITE_OK)
{
NSString *query = #"SELECT * FROM Student";
void* v;
char* err_msg;
sqlite3_stmt *studentStmt;
if(sqlite3_prepare_v2(db, [query UTF8String], -1, &studentStmt, &err_msg)==SQLITE_OK)
{
while (sqlite3_step(studentStmt)==SQLITE_ROW) {
int sno = sqlite3_column_int(studentStmt, 0);
NSString *sname = [NSString stringWithUTF8String: sqlite3_column_text(studentStmt, 1)];
float marks = sqlite3_column_double(studentStmt, 2);
Student *st = [[Student alloc]init];
st.Sno = sno;
st.Sname = sname;
st.marks = marks;
[arrStudents addObject:st];
}
}
}
return arrStudents;
}
#import "SearchBarDB.h"
#import"StudentDbwithsearchbarViewController.h"
- (void)viewDidLoad {
[super viewDidLoad];
StudentDbwithsearchbarViewController *sbd = [[StudentDbwithsearchbarViewController alloc]init];
NSLog(#"%d",[sbd.arrStudents retainCount]);
NSLog(#"%#",sbd.arrStudents);
// arrstudentBase = [sbd.arrStudents copy];
arrMatchedString = [[NSMutableArray alloc]init];
}
Lots of potential problems, no definitive answer without a clue as to what you've tried or how you've determined that it failed.
methods should not be prefixed with get; just call it studentRecords or fetchStudentRecords
your memory management code is all over the place; you'll be leaking that array, at the least.
retainCount is useless, don't call it.
writing raw SQL is a waste of time; at least use a wrapper like FMDB or, better yet, move to CoreData
Best guess for failure: the database doesn't exist or the query fails. Have you stepped through the query code?
I've made a container class to store a single tweet. Its initialized by passing in a dictionary object which is a single tweet.
I then store an array of these 'tweets' which I process through to display in a table.
The project is now finished and I am reviewing everything at the moment and I was wondering is there a better way to do this in the future. Is the memory handled correctly. I declare the string member vars with 'copy' and later in the dealloc I use a 'release' rather than just setting them to 'nil'.
Is my init ok or could that be improved?
Tweet.h
#import
#interface Tweet : NSObject
{
NSString * _userName;
NSString * _tweetText;
NSString * _tweetURL;
}
#property (nonatomic, copy) NSString * userName;
#property (nonatomic, copy) NSString * tweetText;
#property (nonatomic, copy) NSString * tweetURL;
- (id) initWithDict:(NSDictionary *)productsDictionary;
#end
Tweet.m
#implementation Tweet
#synthesize userName = _userName;
#synthesize tweetText = _tweetText;
#synthesize tweetURL = _tweetURL;
- (id) initWithDict:(NSDictionary *)productsDictionary
{
NSDictionary *aDict = [productsDictionary objectForKey:#"user"];
self.userName = [aDict objectForKey:#"screen_name"];
self.tweetText = [productsDictionary objectForKey:#"text"];
NSRange match;
match = [self.tweetText rangeOfString: #"http://"];
if (match.location != NSNotFound)
{
NSString *substring = [self.tweetText substringFromIndex:match.location];
NSRange match2 = [substring rangeOfString: #" "];
if (match2.location == NSNotFound)
{
self.tweetURL = substring;
}
else
{
self.tweetURL = [substring substringToIndex:match2.location];
}
}
else
{
self.tweetURL = nil;
}
return self;
}
-(void) dealloc
{
[self.tweetText release];
[self.tweetURL release];
[self.userName release];
[super dealloc];
}
#end
Many Thanks,
Code
At first sight, I see no inherent flaws here. That looks fine. I would prefer to do:
-(void) dealloc
{
[_tweetText release];
[_tweetURL release];
[_userName release];
[super dealloc];
}
But what you do is good as well.
So in my model I have the following code... I am successfully able to return each individual value. I want to know how am I able to return the entire speakerTable []... Maybe some advice. Thanks!
typedef struct {
NSUInteger speakerID;
NSString * speakerName;
NSString * speakerPosition;
NSString * speakerCompany;
} SpeakerEntry;
static const SpeakerEntry speakerTable [] =
{
{0, #"name", #"position", #"company"},
{1, #"name", #"position", #"company"},
{-1, nil, nil, nil}
};
This works correctly...
-(NSString *) stringSpeakerCompanyForId:(NSUInteger) identifier{
NSString * returnString = nil;
if ([self helpCount] > identifier) {
returnString = speakerTable[identifier].speakerCompany;
}
return returnString;
}
This does not work at all..
-(id) getSpeaker{
//if ([speakerTable[0].speakerName isKindOfClass:[NSString class]])
// NSLog(#"YES");
NSArray * myArray3 = [NSArray arrayWithArray:speakerTable];
return myArray3;
}
arrayWithArray expects an NSArray, not a C array.
The first one works because you are using it like a C array.
Alternatively - don't use a struct, use an object instead:
Create a class called Speaker.
In Speaker.h
#interface Speaker : NSObject {}
#property (nonatomic, assign) NSUinteger id;
#property (nonatomic, copy) NSString name;
#property (nonatomic, copy) NSString position;
#property (nonatomic, copy) NSString company;
- (void)initWithId:(NSUInteger)anId name:(NSString *)aName position:(NSString *)aPosition company:(NSString *)aCompany;
#end
in Speaker.m
#import "Speaker.h"
#implementation Speaker
#synthesize id, name, position, company;
- (void)initWithId:(NSUInteger)anId name:(NSString *)aName position:(NSString *)aPosition company:(NSString *)aCompany {
if (!([super init])) {
return nil;
}
id = anId;
NSString name = [[NSString alloc] initWithString:aName];
NSString position = [[NSString alloc] initWithString:aPosition];
NSString company = [[NSString alloc] initWithString:aCompany];
return self;
}
- (void)dealloc {
[name release];
[position release];
[company release];
[super dealloc];
}
#end
And now in your calling code you can create an immutable array of speakers with:
Speaker *speaker0 = [[Speaker alloc] initWithId:0 name:#"name0" position:#"position0" company:#"company0"];
Speaker *speaker1 = [[Speaker alloc] initWithId:1 name:#"name1" position:#"position1" company:#"company1"];
Speaker *speakerNull = [[Speaker alloc] initWithId:-1 name:nil position:nil company:nil];
NSArray *speakerArray [[NSArray arrayWithObjects: speaker0, speaker1, speakerNull] retain]
[speaker0 release];
[speaker1 release];
[speakerNull release];
note: this is typed straight in, so feel free to mention/correct typos or errors
The method arrayWithArray takes in an NSArray as an argument, not a C array.