Need direction about Binary Search Tree implementation in Objective-C - ios

I have a partial implementation of a binary tree that doesn't work properly. I believe I am missing fundamental knowledge about struct memory management in objective-c but not sure what it is(besides malloc). When I try to create a new tree node based on a struct I get
Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)
which led me to believe I didn't create a memory location for this struct pointer. What is the proper way of doing this in Objective-C? (Code in below)
Thank you for taking the time to respond. The code seems correct from the logic perspective so not sure what the issue is here.
EDIT
I've modified the source code based on #trungduc 's response. But now I am getting a stack overflow in the printDescription method
issue:
Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffeef3fffe8) // on line [self printDescription:root.left];
PS.
I did see this question but didn't help. I also saw this repo but I am not sure happy with some of the implementation details so I ended up not following it. Does anyone know any good guides/tutorials on how to do trees and graphs in Objective-C?
Main.m
#import <Foundation/Foundation.h>
// BSTNode is an Objective-C class
#interface BSTNode : NSObject
#property (nonatomic, assign) int data;
#property (nonatomic, strong) BSTNode *left;
#property (nonatomic, strong) BSTNode *right;
#end
#implementation BSTNode
#end
#interface BST: NSObject
- (BSTNode *)insertNode:(BSTNode *)root withData:(int)data;
- (void)printDescription:(BSTNode *)root;
#end
#implementation BST
- (BSTNode *)initializeTreeNode {
// By default, |data| is 0, |left| is nil, |right| is nil
return [[BSTNode alloc] init];
}
- (BSTNode *)insertNode:(BSTNode *)root withData:(int)data {
if(!root) {
root = [self initializeTreeNode];
root.data = data;
} else if (root.data >= data) {
root.left = [self insertNode:root.left withData:data];
} else {
root.right = [self insertNode:root.right withData:data];
}
return root;
}
- (void)printDescription:(BSTNode *)root {
// in order left - root - right
[self printDescription:root.left];
NSLog(#"%d",root.data);
[self printDescription:root.right];
}
#end
and inside the main method:
int main(int argc, const char * argv[]) {
#autoreleasepool {
BST *bst = [[BST alloc] init];;
BSTNode *root = [[BSTNode alloc]init];
[bst insertNode:root withData:20];
[bst insertNode:root withData:15];
[bst insertNode:root withData:25];
[bst printDescription:root];
}
return 0;
}

You got crash because you called node->data while node is NULL.
In this case, I suggest to define BSTNode as an Objective-C class. You can try my code below.
// BSTNode is an Objective-C class
#interface BSTNode : NSObject
#property (nonatomic, assign) int data;
#property (nonatomic, strong) BSTNode *left;
#property (nonatomic, strong) BSTNode *right;
#end
#implementation BSTNode
#end
#interface BST: NSObject
- (BSTNode *)insertNode:(BSTNode *)root withData:(int)data;
- (void)printDescription:(BSTNode *)root;
#end
#implementation BST
- (BSTNode *)initializeTreeNode {
// By default, |data| is 0, |left| is nil, |right| is nil
return [[BSTNode alloc] init];
}
- (BSTNode *)insertNode:(BSTNode *)root withData:(int)data {
if(!root) {
root = [self initializeTreeNode];
root.data = data;
} else if (root.data >= data) {
root.left = [self insertNode:root.left withData:data];
} else {
root.right = [self insertNode:root.right withData:data];
}
return root;
}
- (void)printDescription:(BSTNode *)root {
if (!root) {
return;
}
// in order left - root - right
[self printDescription:root.left];
NSLog(#"%d",root.data);
[self printDescription:root.right];
}
#end

Related

Use of undeclared identifier 'AIRGoogleMapOverlay' in AIRGoogleMapOverlayManager even after #import "AIRGoogleMapOverlay.h"

I am getting Use of undeclared identifier 'AIRGoogleMapOverlay' error when I am trying to run my react native project through Xcode. I am actually trying to open the app on my iPhone and thats when I encounter this error. If I simply say react-native run-ios, it builds and launches the app on simulator. I am trying to extract current device location which I can't do using a simulator.
The error occurs in the AirGoogleMapOverlayManager.m file which exists in the react-native-google-maps package.
AIRGoogleMapOverlay.h
#ifdef HAVE_GOOGLE_MAPS
#import <Foundation/Foundation.h>
#import <GoogleMaps/GoogleMaps.h>
#import <React/RCTBridge.h>
#import "AIRMapCoordinate.h"
#import "AIRGoogleMap.h"
#interface AIRGoogleMapOverlay : UIView
#property (nonatomic, strong) GMSGroundOverlay *overlay;
#property (nonatomic, copy) NSString *imageSrc;
#property (nonatomic, strong, readonly) UIImage *overlayImage;
#property (nonatomic, copy) NSArray *boundsRect;
#property (nonatomic, readonly) GMSCoordinateBounds *overlayBounds;
#property (nonatomic, weak) RCTBridge *bridge;
#end
#endif
AIRGoogleMapOverlay.m
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapOverlay.h"
#import <React/RCTEventDispatcher.h>
#import <React/RCTImageLoader.h>
#import <React/RCTUtils.h>
#import <React/UIView+React.h>
#interface AIRGoogleMapOverlay()
#property (nonatomic, strong, readwrite) UIImage *overlayImage;
#property (nonatomic, readwrite) GMSCoordinateBounds *overlayBounds;
#end
#implementation AIRGoogleMapOverlay {
RCTImageLoaderCancellationBlock _reloadImageCancellationBlock;
CLLocationCoordinate2D _southWest;
CLLocationCoordinate2D _northEast;
}
- (instancetype)init
{
if ((self = [super init])) {
_overlay = [[GMSGroundOverlay alloc] init];
}
return self;
}
- (void)setImageSrc:(NSString *)imageSrc
{
NSLog(#">>> SET IMAGESRC: %#", imageSrc);
_imageSrc = imageSrc;
if (_reloadImageCancellationBlock) {
_reloadImageCancellationBlock();
_reloadImageCancellationBlock = nil;
}
__weak typeof(self) weakSelf = self;
_reloadImageCancellationBlock = [_bridge.imageLoader loadImageWithURLRequest:[RCTConvert NSURLRequest:_imageSrc]
size:weakSelf.bounds.size
scale:RCTScreenScale()
clipped:YES
resizeMode:RCTResizeModeCenter
progressBlock:nil
partialLoadBlock:nil
completionBlock:^(NSError *error, UIImage *image) {
if (error) {
NSLog(#"%#", error);
}
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#">>> IMAGE: %#", image);
weakSelf.overlayImage = image;
weakSelf.overlay.icon = image;
});
}];
}
- (void)setBoundsRect:(NSArray *)boundsRect
{
_boundsRect = boundsRect;
_southWest = CLLocationCoordinate2DMake([boundsRect[1][0] doubleValue], [boundsRect[0][1] doubleValue]);
_northEast = CLLocationCoordinate2DMake([boundsRect[0][0] doubleValue], [boundsRect[1][1] doubleValue]);
_overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:_southWest
coordinate:_northEast];
_overlay.bounds = _overlayBounds;
}
#end
#endif
And here is where I get the error, in AIRGoogleMapOverlayManager
#import "AIRGoogleMapOverlayManager.h"
#import "AIRGoogleMapOverlay.h"
#interface AIRGoogleMapOverlayManager()
#end
#implementation AIRGoogleMapOverlayManager
- (UIView *)view
{
AIRGoogleMapOverlay *overlay = [AIRGoogleMapOverlay new]; ERROR-Use of undeclared identifier 'AIRGoogleMApOverlay'
overlay.bridge = self.bridge; ERROR-Use of undeclared identifier 'overlay'
return overlay; ERROR-Use of undeclared identifier 'overlay'
return 0;
}
RCT_EXPORT_MODULE()
RCT_REMAP_VIEW_PROPERTY(bounds, boundsRect, NSArray)
RCT_REMAP_VIEW_PROPERTY(image, imageSrc, NSString)
#end
I know that solving the first will get rid of all 3 errors. Also I am running xcworkspace, not xcodeproj.
Any help is appreciated!
I added HAVE_GOOGLE_MAPS=1 to the preprocessor macros, all the AIRGoogleMapOverlay related errors were gone.
This needs to be added for both Debug and Release in case someone is wondering why they are getting this error while trying to create an offline bundle.
You might need a bridging header.
Create a file in your project, named for instance AIRGoogleMapOverlay-Bridging-Header.h
and put
#import "AIRGoogleMapOverlay.h"
in it.
Finally, add the header file in your Build settings like below, depending on the environment you need it to be set up.

iOS thread safe getter deadlocks

I've create a singleton CarQueueClass with a car property which should be thread-safe. I've overridden the getter and setter for this property. When I try to get self.car within this class or access this property from the sharedInstance, it looks like it deadlocks. How can I return a Car in the getter without dispatch_sync deadlocking?
#interface CarQueueClass ()
#property (nonatomic, strong) Car * car;
#property (nonatomic, strong) dispatch_queue_t carQueue;
#end
#implementation CarQueueClass
#synthesize
car = _car
(id)init {
if ([super init]) {
self.carQueue = dispatch_queue_create("appName.SerialQueue", NULL);
}
return self;
}
- (void)setCar:(Car *)sampleCar
{
dispatch_async(self.carQueue, ^{
_car = sampleCar;
});
}
- (Car *)car
{
__block Car * tempCar;
dispatch_sync(self.carQueue, ^{
tempCar = _car;
});
return tempCar;
}

count NSArray from another class

Very basic question here...
I have 2 classes and I want to keep an NSArray in one class and access it in different class.
Questions.h
#import <Foundation/Foundation.h>
#interface Questions : NSObject
#property NSMutableArray *questions;
-(void) questionMethod;
#end
Questions.m
#import "Questions.h"
#implementation Questions
-(void) questionMethod {
NSArray *questionBank = [4,5,6];
}
#end
ViewController.m
#import "Questions.h"
-(void)generateRandomQuestionOrder {
Questions *questions = [[Questions alloc] init];
}
How do I count the values of questionBank array in generateRandomQuestionOrder method?
Not the best naming convention but take a look at the following example. You declare a public property in the Questions object and access it from the controller after you initialised a new object there. You may consider declaring it readonly and set it to readwrite in the private interface extension.
Questions.h
#import <Foundation/Foundation.h>
#interface Questions : NSObject
#property NSMutableArray *questions;
#end
Questions.m
#import "Questions.h"
#implementation Questions
-(id) init {
if (self = [super init]) {
_questions = #[4,5,6];
}
return self;
}
#end
ViewController.m
#import "Questions.h"
-(void)generateRandomQuestionOrder {
Questions *theQuestions = [[Questions alloc] init];
NSLog(#"%#", [theQuestions.questions description]);
}

override property from superclass in subclass

I want to override an NSString property declared in a superclass. When I try to do it using the default ivar, which uses the the same name as the property but with an underscore, it's not recognised as a variable name. It looks something like this...
The interface of the superclass(I don't implement the getter or setter in this class):
//Animal.h
#interface Animal : NSObject
#property (strong, nonatomic) NSString *species;
#end
The implementation in the subclass:
//Human.m
#implementation
- (NSString *)species
{
//This is what I want to work but it doesn't and I don't know why
if(!_species) _species = #"Homo sapiens";
return _species;
}
#end
Only the superclass has access to the ivar _species. Your subclass should look like this:
- (NSString *)species {
NSString *value = [super species];
if (!value) {
self.species = #"Homo sapiens";
}
return [super species];
}
That sets the value to a default if it isn't currently set at all. Another option would be:
- (NSString *)species {
NSString *result = [super species];
if (!result) {
result = #"Home sapiens";
}
return result;
}
This doesn't update the value if there is no value. It simply returns a default as needed.
to access the superclass variables, they must be marked as #protected, access to such variables will be only inside the class and its heirs
#interface ObjectA : NSObject
{
#protected NSObject *_myProperty;
}
#property (nonatomic, strong, readonly) NSObject *myProperty;
#end
#interface ObjectB : ObjectA
#end
#implementation ObjectA
#synthesize myProperty = _myProperty;
#end
#implementation ObjectB
- (id)init
{
self = [super init];
if (self){
_myProperty = [NSObject new];
}
return self;
}
#end

Variable in my iOS app?

I can't belice I am asking this, but im very crazy with this variable stuff.
I want to save a username information. I load them at the load of my view. After this I will get the information when I click on a button.
Here is my code:
#interface SelfViewController : UIViewController
{
NSString *usernameString;
}
- (void)viewDidLoad
{
usernameString = #"test";
}
- (IBAction)goToProfileButtonPressed:(id)sender
{
NSLog(#"%#", usernameString); //CRASH BAD EXEC
}
What did I wrong????
Change your .h file to:
#interface SelfViewController : UIViewController {
    NSString *usernameString;
}
#property (retain, nonatomic) NSString *usernameString;
Then in your .m file:
#synthesize usernameString;
- (void)viewDidLoad {
     self.usernameString = #"test";
}
- (IBAction)goToProfileButtonPressed:(id)sender {
    NSLog(#"%#", self.usernameString); // "self." can be omitted, but it is best practice not to
}
- (void)dealloc {
[usernameString release];
[super dealloc];
}
The problem is that you assign usernameString to an autoreleased string object. By the time the button is pressed, usernameString has been released and has become garbage memory. By retaining it (and subsequently releasing it in -dealloc to avoid a leak) you know that it will not be prematurely released.
You need to synthesize the ivar and add it as a property. (For not-ARC compiling):
in the .h:
#interface SelfViewController : UIViewController
{
NSString *usernameString;
}
#property (nonatomic, retain) NSString *usernameString;
in the .m:
#synthesize usernameString;

Resources