I'm currently battling through some memory leaks and having some serious trouble working out one of the last ones I have left. The leaks instrument shows several leaks all coming from the same method for various different reasons mostly attributed to either NSCFString, NSMutableArray and a class I made called GraphData. I have attempted to fix it in a few different ways to no avail so hopefully some light can be shed on this problem which hopefully is something simple I have overlooked.
Here is some code:
// the offending, leaking method
-(NSMutableArray*)fillDataInArray:(NSInteger)keyphrase_id{
NSLog(#"Keyphrase_id:%d", keyphrase_id);
NSDate *startdate = [self getDateForApplicationInstalled];
NSDate *enddate = [NSDate date];
NSString *dateString1=[[NSString alloc] initWithString: [fmt stringFromDate:startdate]];
NSString *dateString2=[[NSString alloc] initWithString: [fmt stringFromDate:enddate]];
NSMutableArray *newDataNew = [[NSMutableArray alloc]init];
self.newData = newDataNew;
[newDataNew release];
selStmt = nil;
if (!selStmt)
{
const char *sql = "select distinct position, key_time from ranking where keyphrase_id = ? and key_time between ? and ? order by key_time";
if (sqlite3_prepare_v2(database, sql, -1, &selStmt, NULL) != SQLITE_OK)
{
selStmt = nil;
}
NSInteger n = keyphrase_id;
sqlite3_bind_int(selStmt, 1, n);
sqlite3_bind_text(selStmt, 2, [dateString1 UTF8String] , -1, SQLITE_TRANSIENT);
sqlite3_bind_text(selStmt, 3, [dateString2 UTF8String] , -1, SQLITE_TRANSIENT);
NSLog(#"SQL query is: [%s]", sql);
}
if (!selStmt)
{
NSAssert1(0, #"Can't build SQL to read keyphrases [%s]", sqlite3_errmsg(database));
}
int ret;
while ((ret=sqlite3_step(selStmt))==SQLITE_ROW)
{
GraphData *item = [[GraphData alloc]init];
item.key = sqlite3_column_int(selStmt, 0);
item.value = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selStmt,1)];
[newData addObject:item];
[item release], item = nil;
}
sqlite3_reset(selStmt); // reset (unbind) statement
[dateString2 release];
[dateString1 release];
return newData;
}
//GraphData.h
#interface GraphData : NSObject{
NSInteger key;
NSString *value;
}
#property (nonatomic, readwrite) NSInteger key;
#property (nonatomic, retain) NSString *value;
-(id)initWithPrimaryKey:(NSInteger) xid;
-(id)initWithName:(NSString *)n key:(NSInteger)i;
#end
//GraphData.m
#import "GraphData.h"
#implementation GraphData
#synthesize key,value;
-(id)initWithPrimaryKey:(NSInteger) xid{
self.key = xid;
self.value = #"";
return self;
}
-(id)initWithName:(NSString *)n key:(NSInteger)i{
self.key = 0;
self.value = n;
return self;
}
-(void)dealloc{
[value release], value = nil;
[super dealloc];
}
#end
Thanks for looking at my post!
the leak tool tells you where a leaked object has been created. As NSCFString, NSMutableArray and GraphData objects are leaked from this method, let's have a look how this could happen.
You insert GraphData objects (containing string objects) only in an NSMutableArray and they seem to be properly released. So to leak a GraphData object that is created inside this method, the array containing the elements has to be the leak.
Please check the callers of the method. I assume one of them is retaining (and not releasing) the return value of the method.
Also, your initializers have to be changed to call super's init, but this is not related to the leak. An example:
-(id)initWithPrimaryKey:(NSInteger) xid
{
self = [super init];
if (self) {
self.key = xid;
self.value = #"";
}
return self;
}
Related
We can use instruments for various kinds of analysis. But many programmers find this tool to be too complicated and too heavy to bring real value.
Is there a simple way to track all objects of a specific class, and for each to know who exactly was allocating them and to verify that they are being freed correctly?
The answer is yes! there is a way, and I'll demo it in my answer below
Tracking allocations easily:
How to use: you can put the 150 lines of code below into a file named AllocTracker.m and drag it into your project files.
Use the check box at the right pane of Xcode to enable/disable it in your compilation target.
What you'll get?
when enabled, this module will track all allocations and deallocations of UIImage objects and log them. (It can easily be modified for tracking other classes.)
In addition to logging every allocation and deallocation, it will periodically (currently every 15 seconds) dump all objects which are currently allocated, with some added info and the call stack which allocated them.
What is the added value?
This code was used in big projects to get rid of orphan objects which were left allocated without notice, allowing to significantly reduce the memory footprint of the app and fix memory leaks.
So here is the code for AllocTracker.m:
#define TRACK_ALLOCATIONS
#ifdef TRACK_ALLOCATIONS
#import <UIKit/UIKit.h>
#define TIMER_INTERVAL 15
#implementation UIApplication(utils)
+(NSString *)dateToTimestamp:(NSDate *)date
{
if (date == nil) {
date = [NSDate date];
}
static NSDateFormatter *dateFormatter = nil;
if (!dateFormatter) {
dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
[dateFormatter setDateFormat:#"HH:mm:ss.S"];
}
NSString *ts = [dateFormatter stringFromDate:date];
return ts;
}
+(NSString*) getCaller:(int)stackDepth
{
#ifndef DEBUG
return #"NON DBG";
#else
NSArray *symbols = [NSThread callStackSymbols];
int lastIndex = (int)(symbols.count - 1);
if (lastIndex < 3) {
return #"NO DATA";
}
NSMutableString *result = [NSMutableString string];
int foundCount = 0;
for (int ix=3; ix <= lastIndex; ix++) {
NSString *line = symbols[ix];
NSRange rng1 = [line rangeOfString:#"["];
if (rng1.location == NSNotFound) {
continue;
}
NSRange rng2 = [line rangeOfString:#"]"];
NSString *caller = [line substringWithRange:NSMakeRange(rng1.location+1, rng2.location-rng1.location-1)];
if (foundCount > 0) { //not first
[result appendString:#"<--"];
}
[result appendString:caller];
if (++foundCount == stackDepth) {
break;
}
}
return (foundCount > 0) ? result : #"NO SYMBOL";
#endif
}
#end
#implementation UIImage(memoryTrack)
static NSMapTable *g_allocsMap;
static NSTimer *g_tmr;
static NSDate *g_lastDump = nil;
+(void)gotTimer:(NSTimer *)timer
{
[self dumpAllocs];
}
+(void)startTimer
{
static int count = 0;
g_tmr = [NSTimer scheduledTimerWithTimeInterval:15 target:self selector:#selector(gotTimer:) userInfo:#(count++) repeats:YES];
NSLog(#"starting timer %i", count);
}
+(void)cancelTimer
{
[g_tmr invalidate];
g_tmr = nil;
}
+(void)dumpAllocs
{
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
NSMutableString *str = [NSMutableString string];
[str appendString:#"\n#$# ========== Non-freed UIImages =========\n"];
NSMutableArray *sorted = [NSMutableArray array];
//make sure map is not changed while enumerating
static int s_ts_start = -1;
#synchronized (g_allocsMap) {
NSEnumerator *keysEnum = [g_allocsMap keyEnumerator];
UIImage *img;
while (img = [keysEnum nextObject]) {
NSString *value = [g_allocsMap objectForKey:img];
if (value) { //might be nulled because declared as weak
NSUInteger memUsed = CGImageGetHeight(img.CGImage) * CGImageGetBytesPerRow(img.CGImage);
NSString *objData = [NSString stringWithFormat:#"mem=%5ikb, size=%4ix%-4i", (int)(memUsed/1024), (int)img.size.width, (int)img.size.height];
NSString *line = [NSString stringWithFormat:#"%p - %# [%#]\n", img, objData, value];
if (s_ts_start<0) {
s_ts_start = (int)[line rangeOfString:#"["].location + 1;
}
if (line.length > (s_ts_start+10)) {
[sorted addObject:line];
}
}
}
}
if (sorted.count > 0) {
[sorted sortUsingComparator: ^NSComparisonResult(NSString *s1, NSString *s2)
{
//we expect '0x15a973700 - mem=3600kb, size=640x360 [16:14:27.5: UIIma...'
NSString *ts1 = [s1 substringWithRange:NSMakeRange(s_ts_start, 10)];
NSString *ts2 = [s2 substringWithRange:NSMakeRange(s_ts_start, 10)];
return [ts1 compare:ts2];
}];
int ix = 0;
for (NSString *line in sorted) {
[str appendFormat:#"#$# %3i) %#", ix++, line];
}
}
[str appendString:#"#$# ======================================================\n"];
NSLog(#"%#", str);
});
}
+(instancetype)alloc
{
NSString *caller = [UIApplication getCaller:4];
#synchronized (self) {
id obj = [super alloc];
NSLog(#"#$# UIImage alloc: [%p], caller=[%#]", obj, caller);
NSDate *now = [NSDate date];
NSString *value = [NSString stringWithFormat:#"%#: %#", [UIApplication dateToTimestamp:now], caller];
if (!g_allocsMap) {
g_allocsMap = [NSMapTable mapTableWithKeyOptions:NSMapTableWeakMemory valueOptions:NSMapTableStrongMemory];
}
[g_allocsMap setObject:value forKey:obj];
if (!g_lastDump) {
[self startTimer];
g_lastDump = now;
}
return obj;
}
}
-(void)dealloc
{
NSLog(#"#$# UIImage dealloc: [%#]", self);
}
#end
#endif //TRACK_ALLOCATIONS
How it works?
We create a category of UIImage and set our own version for alloc and dealloc. Every allocated object is saved into an NSMapTable object which works like a dictionary but allow storing object with weak pointers.
For convenience we were adding two methods under UIApplication which can be used by other modules if an appropriate header file is created. One method is for formatting the timestamp, and the other is for reading the call stack (only works in debug builds).
Tip for use:
if you use a real device and install idevicesyslog (brew install libimobiledevice), you can use the terminal to see all allocation debug, like this:
idevicesyslog | grep "#\$#"
Novice Programmer - do this for fun and learning..
I am trying to populate 2 UIPickerView's with data from a SQLite query
Every time I run this, I get this error:
-[__NSArrayI length]: unrecognized selector sent to instance
What I'm trying to do is simple, and shouldn't be this painful a problem. Can you please review, and tell me what may be causing the error?
Please note, I have stripped a lot of the "fluffy" code out for the display elements - I am aware that none of this code is causing any of the issues..
FuelEdit.m
#import "FuelEdit.h"
#import "DBManager.h"
#interface FuelEdit ()
#property (nonatomic, strong) DBManager *dbManager;
#end
#implementation FuelEdit
#synthesize regoPicker;
#synthesize locationPicker;
#synthesize datePicker;
- (void)viewDidLoad
{
self.dbManager = [[DBManager alloc] initWithDatabaseFilename:#"fuel.sql"];
regoPicker.delegate = self;
regoPicker.dataSource = self;
locationPicker.delegate = self;
locationPicker.dataSource = self;
[regoPicker setShowsSelectionIndicator:YES];
}
- (void)viewWillAppear{
}
- (NSInteger)numberOfComponentsInPickerView: (UIPickerView *)pickerView
{
if (pickerView == regoPicker) {
return 1;
} else if (pickerView == locationPicker) {
return 1;
} else {
return 1;
}
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
if (pickerView == regoPicker) {
NSString *query = [NSString stringWithFormat:#"SELECT * FROM aircraft"];
// Load the relevant data.
NSArray *results = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];
return results.count;
} else if (pickerView == locationPicker) {
NSString *query = [NSString stringWithFormat:#"SELECT * FROM location"];
// Load the relevant data.
NSArray *results = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];
return results.count;
} else {
return 1;
}
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
if (pickerView == regoPicker) {
NSString *query = [NSString stringWithFormat:#"SELECT acrego FROM aircraft"];
// Load the relevant data.
NSArray *results = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];
if (results !=nil) {
return [results objectAtIndex:row];
} else {
return nil;
}
} else if (pickerView == locationPicker) {
NSString *query = [NSString stringWithFormat:#"SELECT locname FROM location"];
// Load the relevant data.
NSArray *results = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];
if (results != nil) {
return [results objectAtIndex:row];
} else {
return nil;
}
} else {
return 0;
}
}
FuelEdit.h
#import <UIKit/UIKit.h>
#protocol FuelEditDelegate
#end
#interface FuelEdit : UITableViewController <UITableViewDelegate, UITableViewDataSource, UIPickerViewDataSource, UIPickerViewDelegate>
#property (nonatomic, strong) id<FuelEditDelegate> delegate;
#property (weak, nonatomic) IBOutlet UIPickerView *regoPicker;
#property (weak, nonatomic) IBOutlet UIDatePicker *datePicker;
#property (weak, nonatomic) IBOutlet UIPickerView *locationPicker;
#end
DBManager.m:
#import <Foundation/Foundation.h>
#import "DBManager.h"
#import <sqlite3.h>
#interface DBManager()
#property (nonatomic, strong) NSString *documentsDirectory;
#property (nonatomic, strong) NSString *databaseFilename;
#property (nonatomic, strong) NSMutableArray *arrResults;
-(void)copyDatabaseIntoDocumentsDirectory;
-(void)runQuery:(const char *)query isQueryExecutable:(BOOL)queryExecutable;
#end
#implementation DBManager
-(instancetype)initWithDatabaseFilename:(NSString *)system{
self = [super init];
if (self) {
// Set the documents directory path to the documentsDirectory property.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
self.documentsDirectory = [paths objectAtIndex:0];
// Keep the database filename.
self.databaseFilename = system;
// Copy the database file into the documents directory if necessary.
[self copyDatabaseIntoDocumentsDirectory];
}
return self;
}
-(void)copyDatabaseIntoDocumentsDirectory{
// Check if the database file exists in the documents directory.
NSString *destinationPath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
if (![[NSFileManager defaultManager] fileExistsAtPath:destinationPath]) {
// The database file does not exist in the documents directory, so copy it from the main bundle now.
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.databaseFilename];
NSError *error;
[[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:destinationPath error:&error];
// Check if any error occurred during copying and display it.
if (error != nil) {
NSLog(#"Copy Database Error: %#", [error localizedDescription]);
}
}
}
-(void)runQuery:(const char *)query isQueryExecutable:(BOOL)queryExecutable{
// Create a sqlite object.
sqlite3 *sqlite3Database;
// Set the database file path.
NSString *databasePath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
// Initialize the results array.
if (self.arrResults != nil) {
[self.arrResults removeAllObjects];
self.arrResults = nil;
}
self.arrResults = [[NSMutableArray alloc] init];
// Initialize the column names array.
if (self.arrColumnNames != nil) {
[self.arrColumnNames removeAllObjects];
self.arrColumnNames = nil;
}
self.arrColumnNames = [[NSMutableArray alloc] init];
// Open the database.
BOOL openDatabaseResult = sqlite3_open([databasePath UTF8String], &sqlite3Database);
if(openDatabaseResult == SQLITE_OK) {
// Declare a sqlite3_stmt object in which will be stored the query after having been compiled into a SQLite statement.
sqlite3_stmt *compiledStatement;
// Load all data from database to memory.
BOOL prepareStatementResult = sqlite3_prepare_v2(sqlite3Database, query, -1, &compiledStatement, NULL);
if(prepareStatementResult == SQLITE_OK) {
// Check if the query is non-executable.
if (!queryExecutable){
// In this case data must be loaded from the database.
// Declare an array to keep the data for each fetched row.
NSMutableArray *arrDataRow;
// Loop through the results and add them to the results array row by row.
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Initialize the mutable array that will contain the data of a fetched row.
arrDataRow = [[NSMutableArray alloc] init];
// Get the total number of columns.
int totalColumns = sqlite3_column_count(compiledStatement);
// Go through all columns and fetch each column data.
for (int i=0; i<totalColumns; i++){
// Convert the column data to text (characters).
char *dbDataAsChars = (char *)sqlite3_column_text(compiledStatement, i);
// If there are contents in the currenct column (field) then add them to the current row array.
if (dbDataAsChars != NULL) {
// Convert the characters to string.
[arrDataRow addObject:[NSString stringWithUTF8String:dbDataAsChars]];
}
// Keep the current column name.
if (self.arrColumnNames.count != totalColumns) {
dbDataAsChars = (char *)sqlite3_column_name(compiledStatement, i);
[self.arrColumnNames addObject:[NSString stringWithUTF8String:dbDataAsChars]];
}
}
// Store each fetched data row in the results array, but first check if there is actually data.
if (arrDataRow.count > 0) {
[self.arrResults addObject:arrDataRow];
}
}
}
else {
// This is the case of an executable query (insert, update, ...).
// Execute the query.
//BOOL executeQueryResults = sqlite3_step(compiledStatement);
//if (executeQueryResults == SQLITE_DONE) {
if (sqlite3_step(compiledStatement)) {
// Keep the affected rows.
self.affectedRows = sqlite3_changes(sqlite3Database);
// Keep the last inserted row ID.
self.lastInsertedRowID = sqlite3_last_insert_rowid(sqlite3Database);
}
else {
// If could not execute the query show the error message on the debugger.
NSLog(#"DB Error: %s", sqlite3_errmsg(sqlite3Database));
}
}
}
else {
// In the database cannot be opened then show the error message on the debugger.
NSLog(#"%s", sqlite3_errmsg(sqlite3Database));
}
// Release the compiled statement from memory.
sqlite3_finalize(compiledStatement);
}
// Close the database.
sqlite3_close(sqlite3Database);
}
-(NSArray *)loadDataFromDB:(NSString *)query{
// Run the query and indicate that is not executable.
// The query string is converted to a char* object.
[self runQuery:[query UTF8String] isQueryExecutable:NO];
// Returned the loaded results.
return (NSArray *)self.arrResults;
}
-(void)executeQuery:(NSString *)query{
// Run the query and indicate that is executable.
[self runQuery:[query UTF8String] isQueryExecutable:YES];
}
#end
Make sure your results contain only one array it must not be list of array. I am feeling like when you are doing this
return [results objectAtIndex:row];
it is returning a array instead of returning a string. May be your results contain list of arrays. Please verify this thing.
Error is for the unrecognized selector. It means you are calling length function for an array or returning Array instead of string in any of the method.
I have checked your code.Please check in following section:
NSArray *results = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];
if (results !=nil) {
return [results objectAtIndex:row];
}
I think [results objectAtIndex:row] is returning a array instead of the string.
Please let me know the results...
so I've got a barcode scanning app that is supposed to read the barcode, match it up with an entry in a database, and display all other information about the entry.
I'm using a single file DB called trackeddb.sqlite, which was created using terminal and sqlite3 commands. It houses two tables, one for static information about products (each part number is unique and has its own entry) for filling out a 'first scan' entry, and a second table which will house the same product information, but also barcodes. The second table allows the user to store multiple products of the same part number and specs, but using a barcode to create unique entries.
My issue is, when the barcode scans, it's supposed to display information stored in the second table (if the barcode matches). The code is sound, but when I run my barcode through (after an entry is in the second table) it displays no data other than preset text. I've racked my brain over this and I can't figure it out, but I think it may have to do with how I'm referencing my database.
Thanks for your time!
What I am greeted with when I scan the barcodes
This is the sqlite DB
PasteBin link to sqlite db and schema
The database is called from this method
- (id)init {
if ((self = [super init])) {
NSString* sqLiteDb = [[NSBundle mainBundle] pathForResource:#"trackeddb" ofType:#"sqlite"];
if (sqlite3_open([sqLiteDb UTF8String], &_database) != SQLITE_OK) {
NSLog(#"Failed to open database");
}
}
return self;
}
Here are the main portions of my code, the barcode scanner works perfectly so I won't bother posting that bit. This is just for the database.
TrackerDatabase.m
//TrackerDatabase.m
#import "TrackerDatabase.h"
#import "TrackedItems.h"
#import "Barcode.h"
#interface TrackerDatabase()
#end
#implementation TrackerDatabase
static TrackerDatabase *_database;
+ (TrackerDatabase*)database {
if (_database == nil) {
_database = [[TrackerDatabase alloc] init];
}
return _database;
}
- (id)init {
if ((self = [super init])) {
NSString* sqLiteDb = [[NSBundle mainBundle] pathForResource:#"trackeddb" ofType:#"sqlite"];
if (sqlite3_open([sqLiteDb UTF8String], &_database) != SQLITE_OK) {
NSLog(#"Failed to open database");
}
}
return self;
}
- (void)dealloc {
sqlite3_close(_database);
}
- (NSArray *)trackedItems:(NSString *)barcode {
NSMutableArray *retval = [[NSMutableArray alloc] init];
NSString *query = #"SELECT * from Tracked WHERE barcode=";
query = [query stringByAppendingString:barcode];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
char *barcodeChars = (char *) sqlite3_column_text(statement, 0);
char *partNumChars = (char *) sqlite3_column_text(statement, 1);
char *descChars = (char *) sqlite3_column_text(statement, 2);
char *colorChars = (char *) sqlite3_column_text(statement, 3);
char *sizeChars = (char *) sqlite3_column_text(statement, 4);
char *leadChars = (char *) sqlite3_column_text(statement, 5);
char *manufacturerChars = (char *) sqlite3_column_text(statement, 6);
NSString *barcode = [[NSString alloc] initWithUTF8String:barcodeChars];
NSString *partNum = [[NSString alloc] initWithUTF8String:partNumChars];
NSString *desc = [[NSString alloc] initWithUTF8String:descChars];
NSString *color = [[NSString alloc] initWithUTF8String:colorChars];
NSString *size = [[NSString alloc] initWithUTF8String:sizeChars];
NSString *lead = [[NSString alloc] initWithUTF8String:leadChars];
NSString *manufacturer = [[NSString alloc] initWithUTF8String:manufacturerChars];
TrackedItems *items = [[TrackedItems alloc] initWithBarcode:barcode partNum:partNum desc:desc
color:color size:size lead:lead manufacturer:manufacturer];
[retval addObject:items];
}
sqlite3_finalize(statement);
}
return retval;
}
#end
TrackerDatabase.h
//TrackerDatabase.h
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#interface TrackerDatabase : NSObject {
sqlite3 *_database;
}
+ (TrackerDatabase*)database;
- (NSArray *)trackedItems:(NSString*)barcode;
#end
TrackedItems.m
#import "TrackedItems.h"
#implementation TrackedItems
#synthesize barcode = _barcode;
#synthesize partNum = _partNum;
#synthesize desc = _desc;
#synthesize color = _color;
#synthesize size = _size;
#synthesize lead = _lead;
#synthesize manufacturer = _manufacturer;
- (id)initWithBarcode:(NSString *)barcode partNum:(NSString *)partNum desc:(NSString *)desc
color:(NSString *)color size:(NSString *)size lead:(NSString *)lead
manufacturer:(NSString *)manufacturer {
if ((self = [super init])) {
self.barcode = barcode;
self.partNum = partNum;
self.desc = desc;
self.color = color;
self.size = size;
self.lead = lead;
self.manufacturer = manufacturer;
}
return self;
}
- (void) dealloc {
self.barcode = nil;
self.partNum = nil;
self.desc = nil;
self.color = nil;
self.size = nil;
self.lead = nil;
self.manufacturer = nil;
}
#end
TrackedItems.h
#import <Foundation/Foundation.h>
#interface TrackedItems : NSObject {
NSString *_barcode;
NSString *_partNum;
NSString *_desc;
NSString *_color;
NSString *_size;
NSString *_lead;
NSString *_manufacturer;
}
#property (nonatomic, copy) NSString *barcode;
#property (nonatomic, copy) NSString *partNum;
#property (nonatomic, copy) NSString *desc;
#property (nonatomic, copy) NSString *color;
#property (nonatomic, copy) NSString *size;
#property (nonatomic, copy) NSString *lead;
#property (nonatomic, copy) NSString *manufacturer;
- (id)initWithBarcode:(NSString *)barcode partNum:(NSString *)partNum desc:(NSString *)desc
color:(NSString *)color size:(NSString *)size lead:(NSString *)lead
manufacturer:(NSString *)manufacturer;
#end
After a quick look it seems the problem might lie in:
NSString *query = #"SELECT * from Tracked WHERE barcode=";
query = [query stringByAppendingString:barcode];
In your table, barcode is declared as TEXT. So you need to use LIKE instead of =.
What your query string looks like:
SELECT * from Tracked WHERE barcode=123123123123
What it should look like:
SELECT * from Tracked WHERE barcode LIKE '123123123'
If you're sure that you get information from sqlite, check if your tableview is correctly.
I suggest use Core Data, is easy to do and its better than sqlite for iOS
How to display an integer value in a UILabel in ViewDidLoad? I did for text and date and image but how to convert int to string. I was trying with following code
NSString* label=[aa stringWithFormat:#"%d",((Comments *) [self.list objectAtIndex:0]).noofcomm]];
[self.comments2 setText:label];
but didn't work.Please help me.How to set with the Integer with UILabel?
This is my comments.h
#interface Comments : NSObject
{
NSInteger iD;
UIImage *photo;
NSString *name;
NSString *descrp;
NSDate *date;
NSString *msg;
NSInteger noofcomm;
NSInteger nooflikes;
}
#property(nonatomic,assign)NSInteger iD;
#property(nonatomic,retain)UIImage *photo;
#property(nonatomic,retain)NSString *name;
#property(nonatomic,retain)NSString *descrp;
#property(nonatomic,strong)NSDate *date;
#property(nonatomic,retain)NSString *msg;
#property(nonatomic,assign)NSInteger noofcomm;
#property(nonatomic,assign)NSInteger nooflikes;
#end
DBClass.m
#import "DBClass.h"
#import "Comments.h"
#implementation DBClass
- (NSMutableArray *) getMyComments{
NSMutableArray *wineArray = [[NSMutableArray alloc] init];
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"ComntDB.sqlite"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success)
{
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
{
NSLog(#"An error has occured.");
}
const char *sql = "SELECT id, photo,name,descrp, time,msg,comments,likes FROM Com";
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement");
}
//
while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
Comments *MyWine = [[Comments alloc]init];
MyWine.iD = sqlite3_column_int(sqlStatement, 0);
const char *raw = sqlite3_column_blob(sqlStatement, 1);
int rawLen = sqlite3_column_bytes(sqlStatement, 1);
NSData *data = [NSData dataWithBytes:raw length:rawLen];
MyWine.photo = [[UIImage alloc] initWithData:data];
MyWine.name = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,2)];
MyWine.descrp = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 3)];
MyWine.date=[NSDate dateWithTimeIntervalSince1970:sqlite3_column_double(sqlStatement,4)];
MyWine.msg = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,5)];
MyWine.noofcomm = sqlite3_column_int(sqlStatement, 6);
MyWine.nooflikes = sqlite3_column_int(sqlStatement, 7);
[wineArray addObject:MyWine];
}
}
#catch (NSException *exception) {
NSLog(#"An exception occured: %#", [exception reason]);
}
#finally {
return wineArray;
}
}
#end
RootViewController.m
#import "RootViewController.h"
#import "Comments.h"
#import "DBClass.h"
#interface RootViewController ()
#end
#implementation RootViewController
#synthesize list;
#synthesize image2;
#synthesize name2;
#synthesize descrp2;
#synthesize msg2;
#synthesize date2;
#synthesize comments2;
#synthesize likes2;
- (void)viewDidLoad
{
DBClass * mywines =[[DBClass alloc] init];
self.list = [mywines getMyComments];
[self.image2 setImage:((Comments *) [self.list objectAtIndex:0]).photo];
[self.name2 setText:((Comments *) [self.list objectAtIndex:0]).name];
[self.descrp2 setText:((Comments *) [self.list objectAtIndex:0]).descrp];
NSDateFormatter* fmtr = [[NSDateFormatter alloc] init];
[fmtr setDateFormat:#"MM/dd/yy"];
NSString* label_str = [fmtr stringFromDate:((Comments *) [self.list objectAtIndex:0]).date];
[self.date2 setText:label_str];
[self.msg2 setText:((Comments *) [self.list objectAtIndex:0]).msg];
//[self.comments2 setText:((Comments *) [self.list objectAtIndex:0]).noofcomm];
// int solution = 1;
// [self.comments2 setText:[NSString stringWithFormat:#"%d", solution]];
// int solution2 = 1;
// [self.likes2 setText:[NSString stringWithFormat:#"%d", solution2]];
[super viewDidLoad];
}
- (void)viewDidUnload
{
[self setImage2:nil];
[self setName2:nil];
[self setMsg2:nil];
[self setDescrp2:nil];
[self setComments2:nil];
[self setLikes2:nil];
[self setDate2:nil];
[super viewDidUnload];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
NSInteger someInteger = myInteger;
NSString *someString = [NSString stringWithFormat:#"%d", someInteger];
myLabel.text = someString;
or
NSNumber *someNumber = #(myInteger);
NSString *someString = [someNumber stringValue];
myLabel.text = someString;
Both will work.
EDIT:
In your case, it will be something like this:
NSInteger someInteger = ((Comments *) [self.list objectAtIndex:0]).noofcomm;
NSString someString = [NSString stringWithFormat:#"%d", someInteger];
self.comments2.text = someString;
If it's still not working, FOR SURE the problem is somewhere else, and not with the conversion. Check with property noofcomm has a valid value, check if your label reference is ok (test with a random value before the conversion), and somethings like that.
You need to build an NSString
int someInteger = 10;
NSString *someString = [[NSString alloc] initWithFormat:#"%d", someInteger];
You can use something like [NSString string_from_int:42] in LCategory since 0.1.3: https://github.com/superarts/LCategory
_lbl_yourLabel.text=[NSString stringWithFormat:#"%d",[[dic valueForKey:#"your integer value"] intValue]];
On the top left is your label named "yourLabel" , "dic" is your json response dictionary where all the data is coming in key value terms, "your integer value" is the key for which the value will be assign to the label "yourLabel", we have taken intValue because we cannot assign integer value directly to the label.
or you also can try below:
int anyInteger = 13;
NSString *yourString = [[NSString alloc] initWithFormat:#"%d", anyInteger];
self.yourLabel.text = yourString;
My app is crashing due to an over-released object and I have narrowed it down to the early call of dealloc in a custom class. This causes a crash attributed to an NSMutableArray that is using the custom class listed below:
#import <Foundation/Foundation.h>
#interface GraphData : NSObject{
NSInteger key;
NSString *value;
}
#property (nonatomic, readwrite) NSInteger key;
#property (nonatomic, retain) NSString *value;
-(id)initWithPrimaryKey:(NSInteger) xid;
-(id)initWithName:(NSString *)n key:(NSInteger)i;
#end
#import "GraphData.h"
#implementation GraphData
#synthesize key,value;
-(id)initWithPrimaryKey:(NSInteger) xid{
//[super init];
self=[super init];
if (self){
self.key = xid;
self.value = #"";
}
return self;
}
-(id)initWithName:(NSString *)n key:(NSInteger)i{
self=[super init];
if (self){
self.key = 0;
self.value = n;
}
return self;
}
-(void)dealloc{
NSLog(#"Say bye to %#, kids!", self);
[value release], value = nil;
[super dealloc];
}
#end
Weirdly I'm using GraphData in another class and it works without a problem. In this case however the dealloc calls just before I synthesise the NSMutableArray theNewData property; but after I have synthesised it three times.
-(NSMutableArray*)fillDataInArray:(NSInteger)keyphrase_id{
NSLog(#"lsd");
NSLog(#"Keyphrase_id:%d", keyphrase_id);
NSDate *startdate = [self getDateForApplicationInstalled];
NSDate *enddate = [NSDate date];
NSString *dateString1=[[NSString alloc] initWithString: [fmt stringFromDate:startdate]];
NSString *dateString2=[[NSString alloc] initWithString: [fmt stringFromDate:enddate]];
NSMutableArray *newDataNew = [[NSMutableArray alloc]init];
self.theNewData = newDataNew;
[newDataNew release];
selStmt = nil;
// build select statement
if (!selStmt)
{
const char *sql = "select distinct position, key_time from ranking where keyphrase_id = ? and key_time between ? and ? order by key_time";
if (sqlite3_prepare_v2(database, sql, -1, &selStmt, NULL) != SQLITE_OK)
{
selStmt = nil;
}
NSInteger n = keyphrase_id;
sqlite3_bind_int(selStmt, 1, n);
sqlite3_bind_text(selStmt, 2, [dateString1 UTF8String] , -1, SQLITE_TRANSIENT);
sqlite3_bind_text(selStmt, 3, [dateString2 UTF8String] , -1, SQLITE_TRANSIENT);
NSLog(#"SQL query is: [%s]", sql);
}
if (!selStmt)
{
NSAssert1(0, #"Can't build SQL to read keyphrases [%s]", sqlite3_errmsg(database));
}
int ret;
while ((ret=sqlite3_step(selStmt))==SQLITE_ROW)
{
GraphData *item = [[GraphData alloc]init];
item.key = sqlite3_column_int(selStmt, 0);
item.value = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selStmt,1)];
[self.theNewData addObject:item];
[item release];
}
sqlite3_reset(selStmt); // reset (unbind) statement
[dateString2 release];
[dateString1 release];
return theNewData;
}
It's also accessed in a different method:
-(NSMutableArray *) getDataForCharts:(int)seriesIndex{
NSLog(#"speed");
NSDate *startdate = [self getDateForApplicationInstalled];
NSDate *enddate = [NSDate date];
NSString *dateString1=[[NSString alloc] initWithString: [fmt stringFromDate:startdate]];
NSString *dateString2=[[NSString alloc] initWithString: [fmt stringFromDate:enddate]];
NSMutableArray *newDataNew = [[NSMutableArray alloc]init];
self.actionNoteData = newDataNew;
[newDataNew release];
selStmt = nil;
// build select statement
if (!selStmt)
{
const char *sql = "";
if (seriesIndex == 4) sql = "select distinct 105 score, notes_date from notes where iscompleted =1 and domain_id = ? and notes_date between ? and ? order by notes_date";
if (sqlite3_prepare_v2(database, sql, -1, &selStmt, NULL) != SQLITE_OK)
{
selStmt = nil;
}
NSInteger n = domain_id;
sqlite3_bind_int(selStmt, 1, n);
sqlite3_bind_text(selStmt, 2, [dateString1 UTF8String] , -1, SQLITE_TRANSIENT);
sqlite3_bind_text(selStmt, 3, [dateString2 UTF8String] , -1, SQLITE_TRANSIENT);
NSLog(#"SQL query is: [%s]", sql);
}
if (!selStmt)
{
NSAssert1(0, #"Can't build SQL to read keyphrases [%s]", sqlite3_errmsg(database));
}
// loop reading items from list
int ret;
while ((ret=sqlite3_step(selStmt))==SQLITE_ROW)
{
GraphData *item = [[GraphData alloc]init]; // create item
item.key = sqlite3_column_int(selStmt, 0);
item.value = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selStmt,1)];
NSLog(#"Key:%d", sqlite3_column_int(selStmt, 0));
NSLog(#"Value:%s", sqlite3_column_text(selStmt,1));
[self.actionNoteData addObject:item]; // add to list
[item release]; // free item
}
sqlite3_reset(selStmt); // reset (unbind) statement
[dateString2 release];
[dateString1 release];
return actionNoteData;
}
Zombie points to [i release]; but this is the exact statement called earlier which doesn't result in a crash.
if (index == 4) {
dateComponents.day = ([dateComponents day] -1 ) + dataindex + 1;
if (dataForPlotActionNote.count > dataindex) {
if ([dataForPlotActionNote objectAtIndex:dataindex]) {
GraphData *i = (GraphData *) [dataForPlotActionNote objectAtIndex:dataindex];
NSDate *date = [[[NSDate alloc] init] autorelease];
date =[fmt dateFromString:i.value];
datapoint.xValue = date;//[cal dateFromComponents:dateComponents];
datapoint.yValue = [NSNumber numberWithDouble:(i.key)];
[i release];
}
}
}
What could cause the dealloc call to occur halfway through the executing code?
Could making a GraphData property and reseting it each time help keep it alive long enough?
The [i release] problem makes sense. When you get a reference to the object that's inside dataForPlotActionNote you don't increase its retain count, so you shouldn't be reducing the count either.
The places where you use [item release] are different in that you've created those objects with alloc and therefore do have them retained.