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;
}
Related
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
My English is not good, I try to describe the problem clearly.
I know that #property and #synthesize are just to get getter and setter methods. So we can use property by self.x and _x.
And self.x is just to call setter and getter methods.
The result of #property(strong) is get methods as following:
All is in ARC:
#property (nonatomic, strong) NSString *name;
- (NSString *)name {
return _name;
}
- (void)setName:(NSString *)name {
if (_name != name) {
_name = name;
}
}
So, my question is that if the use of #property(strong) is just to get methods, we can use the following.
- (void)setName:(NSString *)name {
if (_name != name) {
__weak _name = name;
}
}
When we use self.name to set setName: method call, and we get a weak name, even we use strong before, it looks right. But there is a other examples.
#protocol TestDelegate <NSObject>
#end
#interface Test : UIView
#property (nonatomic, weak) id<TestDelegate> delegate;
- (instancetype)initWithDelegate:(id<TestDelegate>)delegate;
#end
- (instancetype)initWithDelegate:(id<TestDelegate>)delegate {
self = [super init];
if (self) {
_delegate = delegate;
}
return self;
}
Use in ViewController, all is dealloc, no recycle. Then we use
#property (nonatomic, strong) id<TestDelegate> delegate;
- (instancetype)initWithDelegate:(id<TestDelegate>)delegate {
self = [super init];
if (self) {
self.delegate = delegate;
}
return self;
}
- (void)setDelegate:(id<TestDelegate>)delegate {
__weak _delegate = delegate;
}
All is dealloc, no recycle too. Because we use self.delegate in init method, setDelegate: method call and we get weak delegate, even we use strong before. Then we use _delegate = delegate, it will recycle!!!
It is puzzled for me that we use weak and _delegate = delegate, it run well, but we use strong, _delegate = delegate and custom weak set method, it is recycle.
Thanks!
The delegates must be weak type of properties. This will avoid retain cycle because there can be endless circle of retaining two objects between themselves. With using ARC this is example of using delegate: #property (nonatomic, weak) id <MyObjectDelegate> delegate;
I've got a singleton class named MyManager which holds multiple of properties. One of these properties is a custom class I've made that inherits from NSObject and also holds multiple properties.
One of my ViewControllers changes one of the properties in the MyManager class but for some reason, it also changes a property (with the same name), but inside the custom object.
To explain:
MyManager:
Custom object
objectThatGetsSet (inside custom object)
objectThatGetsSet
Once I set the objectThatGetsSet in MyManager, it also get's set inside the custom object. Why is this and how can I avoid it?
Here's the MyManager header file:
#import <Foundation/Foundation.h>
#import "myClass.h"
#interface MyManager : NSObject
#property (nonatomic, strong) NSDate *objectThatGetsSet;
#property (nonatmoc, strong) myClass *customObject;
+(id)sharedManager;
#end
And here's the implementation file:
#import "MyManager.h"
#implementation MyManager
#synthesize objectThatGetsSet, customObject;
#pragma mark Singleton Methods;
+ (id)sharedManager {
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
-(id)init {
if (self == [super init]) {
}
return self;
}
#end
Here's the custom class header file:
#import <Foundation/Foundation.h>
#interface myClass : NSObject
#property (nonatomic, strong) myClass objectThatGetsSet;
#end
And the implementation file:
#import "WorkLocationModel.h"
#implementation WorkLocationModel
-(id)init {
// Init self
self = [super init];
if (self)
{
// Setup
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject:self.objectThatGetsSet forKey:#"objectThatGetsSet"];
}
-(instancetype)initWithCoder:(NSCoder *)coder {
self = [super init];
if (self)
self.objectThatGetsSet = [coder decodeObjectForKey:#"objectThatGetsSet"];
return self;
}
#end
Please help me with this, thanks a lot!
I am working on a project that contains a Singleton instance of a class called Survey. Within that singleton instance is a property called "itemArray," which is an NSMutableArray that contains any number of instances of an Item class.
My Items class contains several NSInteger properties, but for the purposes of the application, I need to initialize all NSIntegers with a value of -1 instead of the default 0.
Now, for my Survey class (the one with the Singleton instance), I use the following method in the implementation to change the default value of a property:
-(id)init {
if (self = [super init]) {
_thingy = -1;
}
return self;
}
This works, but for some reason, the same exact syntax (with different properties) doesn't work for instances of my Item instances. For what it's worth, the following codeblock is the creation of 2 instances of Item, and their insertion into itemArray. I also tried the Item *item1 = [[Item alloc]init; method to no avail.
Item *item1;
[[[Survey sharedInstance]itemArray]insertObject:item1 atIndex:0];
Item *item2;
[[[Survey sharedInstance]itemArray]insertObject:item2 atIndex:1];
}
I would appreciate any assistance.
!!!!!UPDATE!!!!!
I entered the following conditional:
if (![[Survey sharedInstance]itemArray]){
NSLog(#"Test");
}
And the "test" logged onto the console, so it looks like the itemArray isn't being initialized. I'm not sure how to actually initialize it, though. When I try the following:
[[Survey sharedInstance]addressArray] = [[NSMutableArray alloc]init];
I'm getting an error saying "Expression is not assignable."
Survey.h:
#import <Foundation/Foundation.h>
#interface Survey : NSObject
+(instancetype)sharedInstance;
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *emailAddress;
#property (nonatomic, assign) NSInteger trigger1;
#property (nonatomic, assign) NSInteger trigger2;
#property (nonatomic, assign) NSInteger trigger3;
#property (nonatomic, assign) NSInteger activeItem;
#property (nonatomic, strong) NSMutableArray *itemArray;
#end
Survey.m
#import "Survey.h"
#implementation Survey
+ (instancetype)sharedInstance {
static Survey *_instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[Survey alloc] init];
});
return _instance;
}
-(id)init {
if (self = [super init]) {
_storage = -1;
}
return self;
}
#end
Instead of
[[Survey sharedInstance]addressArray] = [[NSMutableArray alloc]init];
you need to use
[Survey sharedInstance].addressArray = [[NSMutableArray alloc]init];
or
[[Survey sharedInstance] setAddressArray:[[NSMutableArray alloc]init]];
You were trying to assign a value to the return value of a getter method, which is not possible, so the compiler was saying "Expression not assignable." You need to use the setter method or dot notation instead.
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