Search code examples
objective-cinterfacesqlitesingletoninstance-variables

What is the use of placing an instance variable in .h where it wouldn't have a getter and setter ( i.e. nobody can set nor get it)?


I have read Where to put iVars in "modern" Objective-C? and some other questions, but I am still confused.

I am reading from https://www.raywenderlich.com/913/sqlite-tutorial-for-ios-making-our-app SQLite Tutorial:

.h

#import <Foundation/Foundation.h>
#import <sqlite3.h>

@interface FailedBankDatabase : NSObject {
sqlite3 *_database; 
}

+ (FailedBankDatabase*)database;
- (NSArray *)failedBankInfos;

@end

.m

#import "FailedBankDatabase.h"
#import "FailedBankInfo.h"

@implementation FailedBankDatabase

static FailedBankDatabase *_database;

+ (FailedBankDatabase*)database {
    if (_database == nil) {
        _database = [[FailedBankDatabase alloc] init];
    }
    return _database;
}

Please correct where I am wrong: The sqlite3 * database:

  • Isn't a property
  • Doesn't have any synthesize
  • Doesn't have any setter or getter in .m file so no other class can access it--defeating the purpose of placing in .h file

All meaning we can't access nor set it! Why are we doing this?

What what is the purpose of placing this in .h file; Why not just write as a property? Or just write in our .m file alone?

Edit: What is the modern way of using Sqlite3 in Objective-C?


Solution

  • It was not always possible to declare instance variables in the implementation block. It has been possible for several years, but the date of that tutorial is April 8, 2010. When it was written, the author probably wanted it to work on older versions of the compiler.

    Because _database is not declared @private, it is in fact possible to access the instance variable outside of the FailedBankDatabase implementation. In Objective-C, you can treat an object pointer as a struct pointer and access its instance variables like struct fields. So you could do this:

    #import "FailedBankDatabase.h"
    
    int main(int argc, char *argv[])
    {
        FailedBankDatabase *db = [FailedBankDatabase database];
        printf("instance variable: %p\n", db->_database);
        return 0;
    }
    

    That's probably a bad idea, though.

    UPDATE

    Since your sqlite3 *_database is intended to be private, you probably just want to do this:

    FailedBankDatabase.h

    #import <Foundation/Foundation.h>
    
    @class FailedBankInfo;
    
    @interface FailedBankDatabase : NSObject
    
    + (FailedBankDatabase*)database;
    - (NSArray<FailedBankInfo *> *)failedBankInfos;
    
    @end
    

    FailedBankDatabase.m

    #import "FailedBankDatabase.h"
    #import "FailedBankInfo.h"
    #import <sqlite3.h>
    
    @implementation FailedBankDatabase {
        sqlite3 *_database;
    }
    
    static FailedBankDatabase *theInstance;
    
    + (FailedBankDatabase*)database {
        if (theInstance == nil) {
            theInstance = [[FailedBankDatabase alloc] init];
        }
        return theInstance;
    }