Understanding why assign is breaking code in swift - ios

I made an xcframework (in objective c) which is working fine in objective C but throws an error when using swift.
On debugging, I realized that it was breaking in swift because I was using assign.
I went through his answer: https://stackoverflow.com/a/4511004/10433835
where they say this
In most cases you'll want to use weak so you're not trying to access a deallocated object
I didn't quite get what assign does, but I don't think I am trying to access a deallocated object.
This is what I am doing
I have config with these properties
#import <Foundation/Foundation.h>
#interface Config : NSObject
#property(nonatomic, assign, readwrite) NSString *name;
#property(nonatomic, assign, readwrite) NSString *id;
#property(nonatomic, assign, readwrite) NSString *api;
#end
This is my Config.m file
#implementation Config
- (id)init {
if (self = [super init]) {
_api = #"https://api.xyz.in"
}
return self;
}
- (NSMutableDictionary *_Nonnull)configProperties {
if (!_name) {
[NSException raise:#"name" format:#"Room name cannot be null, please set room name"];
}
NSLog(#"Room name: %#", _name);
At this line it will throw Thread 1: EXC_BAD_ACCESS
NSLog(#" name: %#", _name);
if I remove assign, it won't throw any error
How am I calling it?
let config:Config = Config();
config.name = "varun_bindal";
let props = config.configProperties()
Can someone please explain me why using assign in swift is crashing my code? and why not using it doesn't.

You actually don't want a weak or assign set for that property. The object will be deallocated as soon as it is set. You want a strong reference because the object owns the property. weak will nil the pointer as soon as it's set. So checking the pointer will return nil. assign will keep the address of the pointer without keeping the actual memory set. Hence you're pointing to something that has been deallocated. ie: pointing to bad memory location. It's kind of a remnant of the old days really..
You can read here for more info on keywords:
https://exceptionshub.com/property-and-retain-assign-copy-nonatomic-in-objective-c.html

The answer is: It's complicated.
Swift takes care of object ownership for you. Your only responsibility is to create strong or weak variables to avoid retain cycles. When you stay in Swift, it takes care of everything else.
Life is more complicated in Objective-C, and more complicated still when you need to have Objective-C and Swift code interact.
In order for Swift and Objective-C to work correctly together, you have to declare the memory semantics of your Objective-C classes correctly.
When you declare an Objective-C property as assign, you're telling the compiler not to do any memory management on it. Your Swift code won't set up strong references, and won't be notified if the object has been deallocated. If the Objective-C code doesn't need it any more and releases it, and your Swift code tries to reference it, you will crash.
(As mentioned in comments, Objective-C's assign is equivalent to unowned in Swift.)
As Larme says, assign is ok for non-object scalar types, but not for objects.

Related

How to create a new object and assign properties in Objective-C?

I'm trying to bridge an Objective C SDK with React Native and I'm having some trouble. I have a Subclass of NSObject and I'm trying to set some property values but I can't get it to work.
I have tried to change the property in the header, and in the imp file with out any difference.
PrinterSDK.h (which has libPrinterSDK.a)
#interface Printer : NSObject
#property (nonatomic, readonly) NSString* name;
#property (nonatomic, readonly) NSString* UUIDString;
#end
RNPosPrint.m
#interface Printer ()
#property (readwrite) NSString* name;
#property (readwrite) NSString* UUIDString;
#end
RCT_EXPORT_METHOD(printTestPaper:(NSString*)name:(NSString*)uuid)
{
Printer* printer = [[Printer alloc] init];
printer.name = name;
}
But I keep facing issue with the setter for some reason I can't figure out.
ExceptionsManager.js:94 Exception '-[Printer setPrinterName:]: unrecognized selector sent to instance 0x13fd25b90' was thrown while invoking printTestPaper on target RNPosPrint with params (
"Test Printer",
"XXX-XXX-XXX"
)
You do not report the names of your .h and .m files or what else is in the .m – e.g. #implementation of Printer? The class printTestPaper belongs to? Without details like this it is difficult for anyone to help you, you need to help people help you.
That said some points that may help you:
The #interface Printer () where you open up the properties to be writeable should be in the your Printer.m file – in general do not try to open up access to a type's properties from outside the type's implementation, it is both bad design and may not work as you hope (as you just found out).
The code to support a #property is generated by the compiler when it compiles the #implementation, #interface's themselves produce no executable code – they describe the accessible parts of the #implementation.
setter=<name> provides a different name for the auto-created property setter function. While a method <name> will be created to set the property using dot syntax the properties name is still used, e.g. in your case printer.name = ... is still used even with the setter=setPrinterName:. You can call the auto-created method using standard method syntax, that failed in your case for the reasons above.
Using setter=<name> or getter=<name> are really advanced features and you probably will never need to use them – when you do need to use them you will know! Just avoid them till then.
If you wish to provide a method which creates the object and sets properties then do this in the type's implementation. The usual way of doing this is to provide an init method that does this, e.g. in this case it might be - initWithName:(NSString *)printerName { ... }, or an equivalent class method which does the allocation and sets the parameters, e.g. in this case it might be + newWithName:(NSString *)printerName { ... }.
HTH
Since it's an interface from statically linked library it is simply not possible to extend or manipulate. Not without tempering with the compiler.

I have a about iOS Block modifiers and scopes and need help. Description show in full code

I did the experiment as shown in the figure, but I couldn't understand the result.
This is my full code:
#import "ViewController.h"
#interface ViewController ()
#property(nonatomic,strong) void (^DemoBlock4)(void);
#property(nonatomic,copy) void (^DemoBlock5)(void);
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Now is MRC, The copy shoudn't Automatic.
int a = 6;
// //__NSStackBlock__
void (^DemoBlock2)(void) = ^{
NSLog(#"DemoBlock2 %d",a);
};
NSLog(#"DemoBlock2 %#",DemoBlock2);
//__NSMallocBlock__
// This is I executed it manually 'copy',[DemoBlock2 copy] is exactly the same as DemoBLock3
NSLog(#"DemoBlock2.Copy %#",[DemoBlock2 copy]);
void (^DemoBLock3)(void) = [DemoBlock2 copy];
NSLog(#"DemoBlock3 %#",DemoBLock3);
//But why self.DemoBlock4 is same __NSMallocBlock__? And I used the 'strong' modifier.
//self.DemoBlock4 log is exactly the same as self.DemoBlock5(I user 'copy'),
self.DemoBlock4 = ^{
NSLog(#"%d",a);
};
NSLog(#"DemoBlock4 %#",self.DemoBlock4);
self.DemoBlock5 = ^{
NSLog(#"%d",a);
};
NSLog(#"DemoBlock5 %#",self.DemoBlock5);
}
This is Log:
2018-11-30 13:02:35.170860+0800 blocktest[73540:8352045] DemoBlock2 <__NSStackBlock__: 0x7ffeea3b89f8>
2018-11-30 13:02:35.170994+0800 blocktest[73540:8352045] DemoBlock2.Copy <__NSMallocBlock__: 0x60c00005eba0>
2018-11-30 13:02:35.171102+0800 blocktest[73540:8352045] DemoBlock3 <__NSMallocBlock__: 0x60800004ec70>
2018-11-30 13:02:35.171215+0800 blocktest[73540:8352045] DemoBlock4 <__NSMallocBlock__: 0x60c00005f680>
2018-11-30 13:02:35.171320+0800 blocktest[73540:8352045] DemoBlock5 <__NSMallocBlock__: 0x60c00005f0e0>
So, as property copy(like [DemoBlock2 copy]) is automatic, even MRC?
And that makes copy and stronglook the same.
I've read a lot about it and learned that Apple recommends using copy,
But I'd want to know more about what happens when different modifiers are used as property.
So I wrote this Dome.
Like this:
#interface XYZObject : NSObject
#property (copy) void (^blockProperty)(void);
#end
-fno-objc-arc ViewController
Regarding strong vs copy semantics for block properties, you should use copy semantics (and in ARC, this happens automatically). See Programming with Objective-C: Working with Blocks, which says:
Objects Use Properties to Keep Track of Blocks
The syntax to define a property to keep track of a block is similar to a block variable:
#interface XYZObject : NSObject
#property (copy) void (^blockProperty)(void);
#end
Note: You should specify copy as the property attribute, because a block needs to be copied to keep track of its captured state outside of the original scope. This isn’t something you need to worry about when using Automatic Reference Counting, as it will happen automatically, but it’s best practice for the property attribute to show the resultant behavior. For more information, see Blocks Programming Topics.
I can't find a very clear explanation of the semantics of the ARC modifier strong when used for properties in MRC, but it seems that in Clang, strong for properties in MRC means a retaining setter if the property has non-block type, and a copying setter if the property has block type. I found the commit in 2011 in Clang that implemented this behavior.
So that's why your DemoBlock4 is copied -- the property is a strong property of block type, for which Clang produces a synthesized setter that copies the block.
(Note that this is different from retain, which always means a retaining setter even if the property is block type. So if you change DemoBlock4 from strong to retain, you will see that it prints __NSStackBlock__ instead; and the compiler gives you a warning.)

Assign Enum to Variable in Objective-C

How can I assign an enum to a variable and access its value later? I thought this would be pretty simple, but every time I try to assign the enum value to a variable (no type mismatches or warnings in Xcode appear) my app crashes with an EXC_BAD_ACCESS error.
Here's how I setup my enum in my header file (BarTypes.h):
typedef enum {
BarStyleGlossy,
BarStyleMatte,
BarStyleFlat
} BarDisplayStyle;
No issues there (reading and using the values at least). However, when I create a variable that can store one of the enum values (BarStyleGlossy, BarStyleMatte, or BarStyleFlat) then try to set that variable, the app crashes. Here's how I setup and use the variable:
//Header
#property (nonatomic, assign, readwrite) BarDisplayStyle barViewDisplayStyle; //I've also tried just using (nonatomic) and I've also tried (nonatomic, assign)
//Implementation
#synthesize barViewDisplayStyle;
- (void)setupBarStyle:(BarDisplayStyle)displayStyle {
//This is where it crashes:
self.barViewDisplayStyle = displayStyle;
}
Why is it crashing here? How do I store the value of an enum in a variable? I think the issue has to do with a lack of understanding about enums on my end, however if I follow conventional variable setup and allocation, etc. this should work. Any ideas on what I'm doing wrong?
Please note that I'm new to enums, so my vocabulary here may be a bit mixed up (forgive me - and feel free to make an edit if you know what I'm trying to say).
I found a few references about enums across the web:
What is a typedef enum in Objective-C?
Using enum types as properties in Objective C
How to create global enum
How do I define and use an ENUM in Objective-C?
I also tried searching Apple's Developer site but only came up with results about types for Apple APIs (ex. Foundation, UIKit, etc.)
EDIT: Here's how I call the setupBarStyle method:
BarView *bar = [[BarView alloc] init];
[bar setupBarStyle:displayStyle];
Just in case anyone out there is still trying to figure out how to assign an enum value to an enum typed variable or property...
Here is an example using a property.
In the header file...
#interface elmTaskMeasurement : NSObject
typedef NS_ENUM(NSInteger, MeasurementType) {
D,
N,
T,
Y,
M
};
#property(nonatomic) MeasurementType MeasureType;
#end
In the file where the object is created...
elmTaskMeasurement *taskMeasurement = [[elmTaskMeasurement alloc] init];
taskMeasurement.MeasureType = (MeasurementType)N;
The method you implement is called setupBarStyle:, but you call setupBarShape: on the object.
I had this error myself but the error was caused by a different bug I off course create myself.
The setter of my property "myApplicationState" was as follows:
-(void)setApplicationStyle:(myApplicationStyle)applicationStyle{
self.applicationStyle = applicationStyle;
//some more code
}
Off course this would result in an endless loop because in the setter, the setting is called again, and again, and again.
It had to be:
-(void)setApplicationStyle:(myApplicationStyle)applicationStyle{
_applicationStyle = applicationStyle;
//some more code
}

Fix warning: cannot pair a synthesized setter/getter with a user defined setter/getter

I use in my application QHTTPOperation.{h/m} found here all work properly but I got 8 warnings as follow:
Writable atomic property 'acceptableStatusCodes' cannot pair a
synthesized setter/getter with a user defined setter/getter
Writable atomic property 'acceptableContentTypes' cannot pair a
synthesized setter/getter with a user defined setter/getter
Writable atomic property 'authenticationDelegate' cannot pair a
synthesized setter/getter with a user defined setter/getter
...
I am asking because I have noticed that in the project of the above link there is no Warnings related to QHTTPOperation.{h/m}.
Any idea?
Thanks
declare the property nonatomic.
because the compiler does not verify a user-defined accessor's implementation is atomic or nonatomic, it assumes it is not atomic. this is a pretty safe assumption considering the actual implementation uses object level spin locks (in some cases), and the data which backs the implementation is abstracted from us. the only way we could fulfill the contact is by using the (private) runtime functions which the compiler uses, and then the compiler would have to verify the calls and parameters were correct in this scenario. thus, the user-defined accessor is not guaranteed to fulfill the standard objc runtime atomic contract.
Remove the #synthesize for these properties. They provided get/set.
EDIT: For clarity. In the .h, they declare acceptableStatusCodes with
NSIndexSet * _acceptableStatusCodes;
and
#property (copy, readwrite) NSIndexSet * acceptableStatusCodes;
Then, in the .m, they have
#synthesize acceptableStatusCodes = _acceptableStatusCodes;
and
- (NSIndexSet *)acceptableStatusCodes
{
return [[self->_acceptableStatusCodes retain] autorelease];
}
- (void)setAcceptableStatusCodes:(NSIndexSet *)newValue
{
if (self.state != kQRunLoopOperationStateInited) {
assert(NO);
} else {
if (newValue != self->_acceptableStatusCodes) {
[self willChangeValueForKey:#"acceptableStatusCodes"];
[self->_acceptableStatusCodes autorelease];
self->_acceptableStatusCodes = [newValue copy];
[self didChangeValueForKey:#"acceptableStatusCodes"];
}
}
}
These two blocks (the synthesize and the message implemenations) both define the same messages, so they are in conflict. The set message does an extra check at the beginning that the auto-generated synthesize will not do (the check for kQRunLoopOperationStateInited), so I would remove the synthesize, which is being ignored anyway.
The set message is correctly implementing copy semantics with
self->_acceptableStatusCodes = [newValue copy];
And it releases the old value. It also does keyValue change notification. I don't know why they left in the synthesize -- it looks like they might have wanted the state check later, and forgot to remove the auto-generated get/set.

Automatic Reference Counting not working [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why is object not dealloc'ed when using ARC + NSZombieEnabled
I must be doing something wrong here. Compiler is set to Apple LLVM Compiler 3.0 and Objective-C Automatic Reference Counting is set to YES. I also have 3rd Party Software included that requires ARC to be active.
So my basic problem is that my properties don't get released. I have the following header:
#interface ArchiveController : UIViewController <CloseSubviewDelegate> {
NSArray *journals;
NSMutableArray *archiveViews;
}
#property (nonatomic, strong) NSArray *journals;
#property (nonatomic, strong) NSMutableArray *archiveViews;
....
#end
I synthesized those and initialize the archiveViews array like this:
self.archiveViews = [NSMutableArray array];
later I add objects to it, everything works fine; same for the journals array.
I added a dealloc method to check that the ArchiveController gets released:
-(void)dealloc
{
DLog(#"dealloc archive controller");
}
which works, but the arrays are never released; Why? If I change the dealloc method to this:
-(void)dealloc
{
DLog(#"dealloc archive controller");
self.archiveViews = nil;
}
everything works fine, but thats not the way it should be, right? I'm a 100 % certain that the array and its objects aren't referenced anywhere else.
And isn't the Preprocessor supposed to handle the insertion of all the retains/releases/deallocs? when I let Xcode generate preprocessed output, nothing seems changed!
I suspect a circular dependency.
Instruments can help you locate them at times.

Resources