valueForKey: on packed struct? - ios

Given the following packed struct:
typedef struct __attribute__((packed)) {
BOOL flag;
int x;
} Foo;
And the following class:
#interface Obj : NSObject
#property (nonatomic) Foo foo;
#end
#implementation Obj
#end
Trying to call valueForKey: on a property which has type of packed struct:
Obj *obj = [Obj new];
id boo = [obj valueForKey:#"foo"];
causes a crash inside valueForKey: (actually it's crashing not inside valueForKey: but in random places depending on moon magnitude, I guess it's memory corruption).
If I remove __attribute__((packed)) it works fine.
Any possibility to get struct's data without a crash? Is it Apple's bug?
PS. I do need to do it at runtime, i.e. I can't just call .foo directly, I only have #"foo" string at runtime. (What I'm trying to achieve actually is to recursively print object contents).

I don't know if this is possible with properties, but if it is I don't think you're using the right syntax.
Have you tried changing
id boo = [obj valueForKey:#"foo"];
to read
Foo boo = obj.foo;
?
Foo is not nor never will be an id. valueForKey: returns id, and the runtime might be barfing trying to squeeze struct Foo into an NSValue.
If you need to use valueForKey: for some reason, your accesses need to look like.
Foo myFoo = FooFactory();
Object *myObj = [Object new];
[myObj setValue:#( myFoo ) forKey:#"foo"];
Foo myFooOut;
[[myObj valueForKey:#"foo"] getValue:&myFooOut];
//I bet `getValue:` is where things are barfing.
In this case, if NSValue's machinery indeed can't handle the packed struct, you just have to write the accessors the old fashioned way: -<key> and -set:`.
PS: Never name a class "Object", there actually is an Object in some SDKs that NSObject inherits from. I assume that's just in your example.

Avoid KVO for your usage case, and stick to the handy dandy <objc/runtime.h> header. You can re-implement a basic part of KVO using this kind of introspection. Struct packing is used primarily to make sure the compiler doesn't align internal fields properly so the CPU does not need to handle it at the hardware level during execution. In this day and age, it's better to let the compiler take care of things for you.
If you'd really prefer this struct packing (as you said, in a network transmission scenario), I'll need further information to determine where the issue lies. Perhaps attempt to change #property (nonatomic) Foo foo; to #property (nonatomic) NSValue *foo; and then box it and unbox it yourself? This way, the exception/error will be in your application's domain.

Related

Understanding why assign is breaking code in swift

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.

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.)

Dynamically implementing a delegate during runtime

In my class, I have a reference on an UIViewController and want to implement a delegate on this ViewController during runtime. The delegate has only one method (with two parameters) and when the delegate-method on the ViewController is invoked, my class should handle the call.
I am quite sure this is possible with some kind of method swizzling, etc. but I don't know how to accomplish this.
What you want is possible, but it's not method swizzling, since you don't want to switch to methods but add a new one. It can be done, thanks to Objective-C's dynamic nature, but it's still a dirty hack so also file a feature request with the library vendor.
What you want is class_addMethod() and a C function with the actual implementation for that. One more thing, Objective-C methods are C methods, but with two implicit parameters, self and _cmd, which have to keep in mind (both when creating your C method and when telling class_addMethod your methods signature. And here is an SSCE of how to pull something like that off:
#import <Foundation/Foundation.h>
#import <objc/runtime.h> // Required for class_addMethod()
#interface MyClass : NSObject
#end
#implementation MyClass
#end
#protocol MyProtocol <NSObject>
- (void)printString:(NSString *)string;
#end
// Note the method signature containing the
// two implicit parameters self and _cmd!
void MyClassPrinStringIMP(id self, SEL _cmd, NSString *string)
{
NSLog(#"Hi I'm %#:%s and this is the string: %#", self, sel_getName(_cmd), string);
}
void PimpMyClass()
{
// The last argument is the signature. First character is the return type, in our case void
// Then comes self and _cmd, followed by the NSString. You can use #encode() to find out how your
// type is encoded. Best is to build this string at runtime, since the encoding can change with architectures
class_addMethod([MyClass class], #selector(printString:), (IMP)MyClassPrinStringIMP, "v#:#");
}
int main(int argc, const char * argv[])
{
#autoreleasepool
{
PimpMyClass();
id foo = [[MyClass alloc] init]; // id, to silence the compiler!
[foo printString:#"Hello World"];
}
return 0;
}
Example output:
Hi I'm <MyClass: 0x100101810>:printString: and this is the string: Hello World
Edit: Something that you may find is that the passed object is checked at runtime wether it conforms to a protocol or not using conformsToProtocol:. Since this code just adds the method implementation, it would still fail, but you can tell the runtime that you totally do implement that protocol with this one function call:
class_addProtocol([MyClass class], #protocol(MyProtocol));
Alternative: proxies
Objective-Cs dynamism and message forwarding is already praised by #JasperBlues, however, there is one particular class in Objective-C that is designed to do just that: NSProxy. It is designed to intercept sent messages and dispatching them dynamically to the relevant target, and does use the high-level NSInvocation approach. If you can pass a proxied object in some way as the delegate (depending on what your code allows for and what not), creating a NSProxy subclass might be the cleanest way to go.
However, note though that you then end up with a shim object that wraps over your other object, which comes with its own bag of pain and will break when you try to directly access variables via -> syntax. It's not a perfectly invisible proxy, but good enough for most cases.
Firstly, some comments indicate that what you're asking is instantly "a bad thing to do" or a "dirty hack". I disagree here. Most modern Object Oriented languages support these features, and they are used to good effect by numerous system-level frameworks. Of course it is human-nature to perhaps use these dynamic features where they're not really required (for fun or practice), even when a simpler approach would work fine. Beware of this.
Objective-C is admirable in that its somewhat of a legacy language and close to the "bare metal", and yet features a surprising level of dynamism, making it relatively easy to support these requirements without any external libraries or frameworks.
Besides using the class_addMethod guide that another answer correctly indicates, some other approaches are:
Message Forwarding: (recommended)
All NSObject sub-classes have the ability to forward a method that they're not able to respond to, to another target object. This is similar to the lower-level concept of trampolines. Apple publishes a guide on using this approach.
The advantages of using forward invocation is that it uses the NSInvocation level of abstraction, instead of directly calling the C ObjC runtime API. This abstracts the following details away:
Structs and primitives will be box/unboxed automatically
Dispatching to methods with a dynamic/unknown number of arguments becomes easy. Until arm64, this could be done using va_args, however on arm64 va_args can be copied directly to registers, and not popped off the stack.
Resolve Instance Method:
Instance methods are created by by registering a C function as the implementation to respond to a given message. This can be done neatly with blocks, using IMP_ImplementationWithBlock:
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
IMP imp = imp_implementationWithBlock((__bridge id) objc_unretainedPointer(
^(id me, BOOL firstParam, NSString* secondParam)
{
//Implementation goes in here
return something; //something of type 'id'
}));
class_addMethod(self, sel, imp, "##:");
return YES;
}
return NO;
}
Using libffi:
Libffi can also do this kind of thing, though it should not be necessary if you're using pure Objective-C, as the runtime already has these features baked in.

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
}

Resources