Tesseract initialization error - tesseract

Using this github page, https://github.com/robmathews/OCR-iOS-Example, I downloaded and installed the repo and followed the instructions. Trying to launch the .xcodeproj file on my phone gives an exception in Tesseract.mm:
- (id)initWithDataPath:(NSString *)dataPath language:(NSString *)language {
self = [super init];
if (self) {
_dataPath = dataPath;
_language = language;
_variables = [[NSMutableDictionary alloc] init];
[self copyDataToDocumentsDirectory];
_tesseract = new tesseract::TessBaseAPI();
BOOL success = [self initEngine];
if (!success) {
return NO;
}
}
return self;
}
On the return NO line, xcode says Cannot initialize return object of type 'Tesseract *' with an rvalue of type 'BOOL' (aka 'bool').
What am I doing wrong?

NO is a bool value. The return type is (as you defined) id (should be instancetype )
You've to return nil there.

Related

Cannot init a class object - xcode

I'm new to IOS development. I wrote the implementation file following like this.
#implementation Utils
+(id)alloc
{
return [self instance];
}
+(Utils *)instance
{
static Utils *utils = nil;
if (!utils) {
utils = [self init];
}
return utils;
}
-(Utils *)init
{
self = [super init];
if (self) {
mConst = [Constants instance];
mCONT_REGEXP = [mConst CONT_REGEXP];
}
return self;
}
When i call
[Utils instance];
I got the error following Like this:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** +[Utils<0xbff54> init]: cannot init a class object.'
Thanks for your answers.
Are you trying to create a shared singleton instance?
In that case, use the following snippet:
+ (id)sharedInstance;
{
static dispatch_once_t onceToken;
static Utils *sharedUtilsInstance = nil;
dispatch_once( &onceToken, ^{
sharedUtilsInstance = [[Utils alloc] init];
});
return sharedUtilsInstance;
}
It is better to call it "sharedInstance" so that it's more understandable the instance is shared.
remove your following method
+(id)alloc
{
return [self instance];
}
And write code as/....
+(Utils *)instance
{
static Utils *utils = nil;
if (!utils) {
unit = [[unit alloc] init];
}
return utils;
}

Detect Missing JSON Keys With Nested Objects

Currently I am in the process of working with an API that is still in development. Due to this, the keys in the response are still changing. I have successfully been able to retrieve and parse the JSON data from the API into an NSDictionary, and then use this NSDictionary to map the values into custom objects. The approach I am using is the following
-(id)initWithDictionary:(NSDictionary*)dictionary
{
if(self = [super init]){
_ID = [dictionary valueForKey:kKEY_ID];
_name = [dictionary valueForKey:kKEY_NAME];
_nestedObject = [[NestedObject alloc]initWithDictionary:[dictionary valueForKey:kKEY_NESTED_OBJECT]];
//etc...
}
return self
}
Each nested object also contains the same parsing structure.
This works fine except for when the API changes. When something does change, required values do not exist and this causes unexpected behavior or crashes.
Ideally, if one of the keys change, I would like to produce a NSError that I can use to print the value that has changed helping me more quickly find the change and rectify it.
The only alternative approach that I have currently been able to come up with I feel is messy and unmaintainable.
-(id)initWithDictionary:(NSDictionary*)dictionary andError:(NSError**)error
{
if(self = [super init]){
BOOL _parsedSuccessfully = TRUE;
if (_parsedSuccessfully) {
_ID = [dictionary valueForKey: kKEY_ID];
if (!_ID){
_parsedSuccessfully = FALSE;
*error = [NSError parsingErrorFromKey: kKEY_ID];
}
}
if (_parsedSuccessfully) {
_name = [dictionary valueForKey: kKEY_NAME];
if (!_name){
_parsedSuccessfully = FALSE;
*error = [NSError parsingErrorFromKey: kKEY_NAME];
}
}
if (_parsedSuccessfully) {
_nestedObject = [[NestedObject alloc]initWithDictionary:[dictionary valueForKey:kKEY_NESTED_OBJECT]];
if (!_nestedObject){
_parsedSuccessfully = FALSE;
*error = [NSError parsingErrorFromKey: kKEY_NESTED_OBJECT];
}
}
//etc...
if (!_parsedSuccessfully) {
return nil;
}
}
return self
}
I was wondering if anyone else had any other better approaches that preferably uses much less duplication.
Any help would be greatly appreciated.
Add an isValid method to your object, which can be used in any situation, not just when initialised from the JSON dictionary.
- (BOOL)isValid:(NSError **)error {
#define CHECK_NOT_NULL(x, key) if (!x) { \
if (error != NULL) \
*error = [NSError parsingErrorFromKey:key]; \
return NO; \
}
#define CHECK_NOT_EMPTY(x, key) if (!x || ![x length]) { \
if (error != NULL) \
*error = [NSError parsingErrorFromKey:key]; \
return NO; \
}
CHECK_NOT_NULL(_ID, kKEY_ID);
CHECK_NOT_EMPTY(_name, kKEY_NAME);
// etc.
return YES;
#undef CHECK_NOT_NULL
#undef CHECK_NOT_EMPTY
}
And then use this in your init method:
- (id)initWithDictionary:(NSDictionary*)dictionary andError:(NSError**)error
{
if (self = [super init]) {
_ID = [dictionary valueForKey: kKEY_ID];
_name = [dictionary valueForKey: kKEY_NAME];
// etc.
if (![self isValid:error]) {
self = nil; // Assuming ARC
}
}
return self;
}
If you create an array of your keys then you can run your check in a loop so you only have one copy of the loop.
Again, using the array you could get all of the keys from the dictionary and remove them from each other. One way will give you new keys and the other way will give you the missing keys.

IOS Memory leak in class method

In your opinion if I have a singleton subclass of NSObject being initialised with parameters like this:
- (MyObject *) initWithSomeParam:(NSString *)param{
self = [super init];
if (SharedInstance == nil){
SharedInstance = [super init];
SharedInstance.someProperty = param;
}
return self;
}
+ (MyObject *) objectWithSomeParam:(NSString *)param{
return [[self alloc] initWithSomeParam:param];
// Will the alloc cause a leak?
}
The user doesn't have access to the instance method, just the class. Thanks.
That's not the normal way of implementing a singleton and you are breaking the convention of init. Better would be to create a sharedInstance class method and leave the initWithParam method to be more conventional:
static MyObject *_sharedInstance = nil;
+ (MyObject *)sharedInstance:(NSString *)param
{
if (_sharedInstance == nil)
{
_sharedInstance = [MyObject alloc] initWithParam:param];
}
return _sharedInstance;
}
// This must be called during app termination to avoid memory leak
+ (void)cleanup
{
[_sharedInstance release];
_sharedInstance = nil;
}
- (id)initWithParam:(NSString *)param
{
self = [super init];
if (self != nil)
{
self.someProperty = param;
}
return self;
}
However, even that doesn't seem very comfortable; i.e. what happens if the user calls sharedInstance with a different parameter? Perhaps you want to keep a NSMutableDictionary of the initialized objects and create/return them depending on the parameter?
If so, you would do:
static NSMutableDictionary _sharedInstances = [[NSMutableDictionary alloc] init];
+ (MyObject *)sharedInstance:(NSString *)param
{
MyObject *obj = [_sharedInstances objectForKey:param];
if (obj == nil)
{
obj = [[MyObject alloc] initWithParam:param];
[_sharedInstances setObject:obj forKey:param];
}
return obj;
}
// This must be called during app termination to avoid memory leak
+ (void)cleanup
{
[_sharedInstances release];
_sharedInstances = nil;
}

MKAnnotation constructor error

I'm having a problem with MKAnnotation, i created a class "cgdMapAnnotation" for annotations and one of it's constructor is like this:
+ (id) initWithCoordinate:(CLLocationCoordinate2D)coordinate andTitle:(NSString*) title andSubtitle:(NSString*) subtitle {
self = [super alloc];
_coordinate = coordinate;
_title = [title retain];
_subtitle = [subtitle retain];
return self;
}
The problem is that when i call:
cgdMapAnnotation *placemark=[[[cgdMapAnnotation alloc] initWithCoordinate:centerCoordinate andTitle:#"Title" andSubtitle:#"SubTitle" ] autorelease];
I get in the console the following error:
-[cgdMapAnnotation initWithCoordinate:andTitle:andSubtitle:]: unrecognized selector sent to instance 0x33cf2fe0
I really don't understand what's the problem. Can someone help?
Thanks in advance.
First, convention has it that class names start with a capital letter. So cgdMapAnnotation should be CgdMapAnnotation or CGDMapAnnotation.
Second, there are a few problems with initWithCoordinate:andTitle:andSubtitle:.
It is declared as a class method using the '+' at the beginning of the name, but you are attempting to use it as an instance method. [cgdMapAnnotation alloc] will return an instance of cgdMapAnnotation. So you are
self = [super alloc] does not make sense in this class method.
Your method should probably look like this:
- (id)initWithCoordinate:(CLLocationCoodinate2D)coordinate andTitle:(NSString*) title andSubtitle:(NSString*) subtitle
{
if( self = [super init] )
{
_coordinate = coordinate;
_title = [title retain];
_subtitle = [subtitle retain];
}
return self;
}

Imlementation of Singleton Class

i have been using mostly the appDelegate class for global variables but recently i came to know that its not a gud way for keeping global variables so i am trying to make a singleton class as following
#implementation globalVar
static globalVar *_sharedInstance =nil;
#synthesize totalTime;
- (id) init
{
if (self = [super init])
{
}
return self;
}
+ (globalVar *) sharedInstance
{
#synchronized (self) {
if (_sharedInstance == nil) {
[[self alloc] init];
}
}
return _sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
#synchronized(self) {
if (_sharedInstance == nil) {
_sharedInstance = [super allocWithZone:zone];
return _sharedInstance;
}
}
return nil;
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
-(NSUInteger)retainCount
{
return NSUIntegerMax; //denotes an object that cannot be released
}
- (void)release
{
// do nothing
}
- (id)autorelease
{
return self;
}
- (void) setTotalTime:(NSString *)time
{
#synchronized(self) {
if (totalTime != time) {
[totalTime release];
totalTime = [NSString stringWithFormat:#"%#",time];
}
}
//NSLog(#"time %#",totalTime);
}
-(NSString *)getTotalTime
{
#synchronized(self) {
//NSLog(#"total %#",totalTime);
return totalTime;
}
}
when i set the value for totaltime in my appDelegate class and retrieve it in that class only i get the correct value. but when i only retrieve the value in some other class i get BAD EXCESS. i first create the sharedinstance and then only call this method then why am i getting this error??
globalVar *myEngine = [globalVar sharedInstance];
NSLog(#"about %#",[myEngine totalTime]);
in my app delegate
globalVar *myEngine = [globalVar sharedInstance];
[myEngine setTotalTime:totalTime];
NSLog(#"in app delegate%#",[myEngine getTotalTime]);
You're releasing totalTime but not retaining the new value, which means that when you access it it's already been released, causing a bad access exception.
You can correct this by changing the line where you set the value to include a call to retain:
totalTime = [[NSString stringWithFormat:#"%#",time] retain];
Have a look at the discussion here:
Is it good practice to use AppDelegate for data manipulation and Handling?