What does the 'class' function mean in Objective-C? - objective-c

#interface Soka : NSObject
#property (nonatomic, copy) NSString * name;
-(void)speak;
#end
#implementation Soka
-(void)speak{
NSLog(#"my name is: %#", self.name);
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSString * asdfasdfasdfsdf = #"xxxxxxx4";
id cls = [Soka class];
void * obj = &cls;
[(__bridge id)obj speak];
}
return 0;
}
The output is :
[14402:5468392] my name is: xxxxxxx4
Can anyone explain this??
How was the asdfasdfasdfsdf values set to class property?
Thanks
Thanks for all your guys' replies:
Making An Update:
#Leo
Thanks for your reply.
1# What is the meaning of Soka Class object cls, what is its memory structure. It's pointer pointing to what address?
2# find memory near the ocObj object? what if the nearest memory is an integer value? It's a part of OBJC or whatelse theory?

Well it is a little tricky,not useful. It is about Objective C instance memory
Your code can be converted to this
NSString * asdfasdfasdfsdf = #"xxxxxxx4";
Class cls = [Soka class];
void * obj = &cls;
id ocObj = (__bridge id)obj;
NSLog(#"%#",[ocObj name]);
Lets make it clear one by one
cls is a Soka Class object
Class cls = [Soka class];
obj is a pointer point to Soka Class object
void * obj = &cls;
This convert obj to Object C object
id ocObj = (__bridge id)obj;
When call this [ocObj name],Objective C will find memory near the ocObj object.It is #"xxxxxxx4" in the stack.
Also,I test this to make sure I am right
#interface Soka : NSObject
#property (nonatomic, copy) NSString * name;
#property (nonatomic,copy) NSString * address;
-(void)speak;
#end
#implementation Soka
-(void)speak{
NSLog(#"my name is: %#", self.name);
}
#end
int main(int argc, char * argv[]) {
#autoreleasepool {
NSString * asdfasdfasdfsdf = #"xxxxxxx4";
NSString * address = #"address";
Class cls = [Soka class];
void * obj = &cls;
id ocObj = (__bridge id)obj;
NSLog(#"%#",[ocObj name]);
NSLog(#"%#",[ocObj address]);
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
This will log
2015-07-01 23:26:56.857 OCTest[10910:347815] address
2015-07-01 23:26:56.859 OCTest[10910:347815] xxxxxxx4
Update:
+class function will return the class object of one class and type is Class.
So,what is Class type,it is something about objective c runtime
typedef struct objc_class *Class;
This is the define of objc_class
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
When you create an Objective C object,it will auto manage the memory. In your code,it is just a trick to make an Objective C object like memory.

Actually objective-c's classes is structures with properties.
For your's class Soka you have hidden fields in that structure: _name and class. They placed in same order, as placed your's variables asdfasdfasdfsdf and cls.
All works fine because at address &cls placed variable of type Class, that describes class. So after casting obj to id runtime find required field, that describes class and trust that that pointer points at Soka. Of course it'f false, but by circumstances that variables placed at same order and at right places this code work and doesn't crush.
You can't alloc objective-c objects in stack and should avoid this code if you think that you can alloc objective-c object in such way. Because it can lead to unpredicted errors.

The class method gives you the type of an object.
For example, if you want to know if myObject is an NSString, you could do this:
[myObject isKindOfClass:[NSString class]]
isKindOfClass takes a type as its argument, so we call class on NSString to get the type.
It's like typeof in the C languages.

Related

ObjectC-Why can't I get the properties correctly using the class_copyPropertyList function?

macOS 11.5.2
Xcode 13.2.1
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <iostream>
int main(int argc, const char * argv[]) {
#autoreleasepool {
Class clazz = NSClassFromString(#"NSString");
uint32_t count = 0;
objc_property_t* properties = class_copyPropertyList(clazz, &count);
for (uint32_t i = 0; i < count; i++){
const char* name = property_getName(properties[i]);
std::cout << name << std::endl;
}
free(properties);
}
return 0;
}
I will take some snippets of the output:
hash
superclass
description
debugDescription
hash
superclass
description
debugDescription
vertexID
sha224
NS_isSourceOver
hash
superclass
description
debugDescription
...
From the output, we can find that properties such as hash, description, superclass, etc. will appear repeatedly several times, while some properties (such as UTF8String) do not appear in the result list.
How should I get the list of properties correctly?
I would appreciate it.
The reason you're not seeing UTF8String come up as a property is that it's not declared as a property in the main declaration of NSString, but rather in a category. On macOS 12.2.1/Xcode 13.2.1, the declaration of NSString boils down to this:
#interface NSString : NSObject <NSCopying, NSMutableCopying, NSSecureCoding>
#property (readonly) NSUInteger length;
- (unichar)characterAtIndex:(NSUInteger)index;
- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
#end
All other properties and methods on NSString are declared in categories immediately afterwards:
#interface NSString (NSStringExtensionMethods)
#pragma mark *** Substrings ***
/* To avoid breaking up character sequences such as Emoji, you can do:
[str substringFromIndex:[str rangeOfComposedCharacterSequenceAtIndex:index].location]
[str substringToIndex:NSMaxRange([str rangeOfComposedCharacterSequenceAtIndex:index])]
[str substringWithRange:[str rangeOfComposedCharacterSequencesForRange:range]
*/
- (NSString *)substringFromIndex:(NSUInteger)from;
- (NSString *)substringToIndex:(NSUInteger)to;
// ...
#property (nullable, readonly) const char *UTF8String NS_RETURNS_INNER_POINTER; // Convenience to return null-terminated UTF8 representation
// ...
#end
When a property is declared in a category on a type like this, it doesn't get emitted as an actual Obj-C property because categories can only add methods to classes, and not instance variables. When a category declares a property on a type, it must be backed by a method and not a traditional property.
You can see this with a custom class, too — on my machine,
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#interface MyClass: NSObject
#property (nullable, readonly) const char *direct_UTF8String NS_RETURNS_INNER_POINTER;
#end
#interface MyClass (Extensions)
#property (nullable, readonly) const char *category_UTF8String NS_RETURNS_INNER_POINTER;
#end
#implementation MyClass
- (const char *)direct_UTF8String {
return "Hello, world!";
}
- (const char *)category_UTF8String {
return "Hi there!";
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
Class clazz = NSClassFromString(#"MyClass");
printf("%s properties:\n", class_getName(clazz));
uint32_t count = 0;
objc_property_t* properties = class_copyPropertyList(clazz, &count);
for (uint32_t i = 0; i < count; i++){
printf("%s\n", property_getName(properties[i]));
}
free(properties);
puts("-----------------------------------------------");
printf("%s methods:\n", class_getName(clazz));
Method *methods = class_copyMethodList(clazz, &count);
for (uint32_t i = 0; i < count; i++) {
SEL name = method_getName(methods[i]);
printf("%s\n", sel_getName(name));
}
free(methods);
}
return 0;
}
outputs
MyClass properties:
direct_UTF8String
-----------------------------------------------
MyClass methods:
direct_UTF8String
category_UTF8String
If you remove the actual implementations of the *UTF8String methods from the class, the property remains declared, but the category method disappears (because it doesn't actually have a synthesized implementation because of how categories work):
MyClass properties:
direct_UTF8String
-----------------------------------------------
MyClass methods:
direct_UTF8String
As for how to adjust to this: it depends on what purpose you're trying to fetch properties for, and why you might need UTF8String specifically.
NSString declares in its interface it implements methods, but it does not actually implement them, that is why when you print at runtime a list of the its methods it does not print what you expect.
The methods are implemented by other private classes, and when you initialize a new instance of NSString, instead of getting an instance of NSString you get an instance of that private class that have the actual implementation.
You can see that by printing the class type of a string, the following prints NSCFString or NSTaggedPointerString, not NSString:
NSString* aString = [NSString stringWithFormat: #"something"];
NSLog(#"%#", [aString class]);
And this prints __NSCFConstantString:
NSLog(#"%#", [#"a constant string" class]);
This pattern is called a class cluster pattern.
If you modify to dump the methods of the NSCFString you will get a "redactedDescription", it seems you are prevented to query these classes.

Why does my Objective-C dot accessor behaves differently with an implicit getter?

In the following code, I get '(null)' for the second line in the output but not the fourth.
MyClass.h
#interface MyClass : NSObject
#property (readonly) NSString *foo;
#property (getter=getBar, readonly) NSString *bar;
#end
main.m
#implementation MyClass
- (NSString *)getFoo { return #"foo"; }
- (NSString *)getBar { return #"bar"; }
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
MyClass *myClassInstance = [MyClass new];
NSLog(#"%#", myClassInstance.getFoo);
NSLog(#"%#", myClassInstance.foo);
NSLog(#"%#", myClassInstance.getBar);
NSLog(#"%#", myClassInstance.bar);
}
return 0;
output
foo
(null)
bar
bar
Why am I seeing this?
Remember that Objective C getters are just the name of the property; foo in the foo case. In this, there's no relationship between getFoo and foo, so you access the underlying property via its normal getter. It's never been set, so it's nil, which logs as null.
In the later case, you establish the getter for bar as getBar. Thus, accessing bar the property evaluates the getter function you specified.

Can I have a weak static pointer?

Can I have a static pointer that is weak in objective-c? I know it compiles, but I want to know if it will behave as I expect a weak pointer to behave.
__weak static HMFSomeClass *weakStaticPointer;
Yes, that behaves like a proper weak pointer:
__weak static NSObject *weakStaticPointer;
int main(int argc, char * argv[])
{
#autoreleasepool {
NSObject *obj = [NSObject new];
weakStaticPointer = obj;
NSLog(#"%#", weakStaticPointer);
obj = nil; // object is deallocated -> weak pointer is set to nil
NSLog(#"%#", weakStaticPointer);
}
return 0;
}
Output:
<NSObject: 0x100106a50>
(null)
Also I cannot find any restrictions in the Clang/ARC documentation that forbids
a weak pointer to be static.

How to store values in a C structure without losing them when calling structure

I have a C (Objective-C) structure defined:
struct ResultadoVentaPUP{
NSString *autenticadoPorPin1;
NSString *autenticadoPorPin2;
NSString *tipoPago;
NSString *importe;
};
Then I declare a variable of this type globally (at top of the file):
ResultadoVentaPUP resven;
In a function I set values for this structure, for example:
resven.importe=#"12.45";
but when I try to view the content of "importe" in another function from the same file), ir returns (null).
NSLog(#"Result: %#",resven.importe);
What am I doing wrong? should I define the struct with 'static'?
Thank you!
Storing Obj-C objects in a C structure is a rather bad idea nowadays anyway, with ARC (Automatic Reference Counting), it is not even allowed any longer (the compiler will complain if you do that). Why not using an object instead? If you don't want to use assessor methods because you fear the overhead, just use an object with public ivars. Public ivars are bad IMHO, yet a struct is pretty much the same as an object with public ivars.
#interface ResultadoVentaPUP : NSObject
{
#public
NSString * autenticadoPorPin1;
NSString * autenticadoPorPin2;
NSString * tipoPago;
NSString * importe;
}
#end
#implementation ResultadoVentaPUP
#end
ResultadoVentaPUP * resven;
void someFunction () {
resven = [[ResultadoVentaPUP alloc] init];
resven->importe = #"12.45";
}
void someOtherFunction () {
NSLog(#"Result: %#",resven->importe);
}
This code will also work nicely if you use ARC and sooner or later every project should migrate to ARC in the near future (as soon as it can drop support for OSX/iOS versions without ARC support).
Maybe your declaration should be struct ResultadoVentaPUP resven;. This works for me:
#import <Foundation/Foundation.h>
struct ResultadoVentaPUP{
NSString *autenticadoPorPin1;
NSString *autenticadoPorPin2;
NSString *tipoPago;
NSString *importe;
};
struct ResultadoVentaPUP resven;
void func1() {
resven.importe = #"12.45";
}
void func2() {
NSLog(#"Result: %#", resven.importe);
}
int main(int argc, char *argv[]) {
NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];
func1();
func2();
[p release];
}
And I would be remiss if I didn't include the caveat that any time you are using global variables you should seriously be reconsidering your design.

accessor-Objective C

I am new to Objective C.
I need to know how to access the instance variable using the accessors.
I could able to access integer variables but not the character variable which i have declared here.
Please correct if there is any wrong in this code below.
#define SIZE = 4096
#interface data : NSObject
{
unsigned char id[SIZE];
}
#property(readwrite)unsigned char id[SIZE];
#end
#implementation data
#synthesize unsigned char id[SIZE];
#end
main.m
someClass* classPointer = [[someClass alloc]init];
data* dt = [[data alloc]init];
[classPointer createMessage:data.id];
Why not use an instance of NSString or NSData for the instance variable instead of an array of chars? For example:
#interface Foo2 : NSObject
{
NSString *_dataId;
}
#property (nonatomic, retain) NSString *dataId;
#end
#implementation Foo2
#synthesize dataId = _dataId;
#end
Otherwise you'd have to do something along these lines:
#define DATA_ID_SIZE 4096
#interface Foo : NSObject
{
char _dataID[DATA_ID_SIZE];
}
#property (nonatomic, assign) const char *dataID;
#end
#implementation Foo
// Returns a copy of the internal array of chars.
- (const char *)dataID
{
size_t length = strlen(_dataID);
// Dynamically allocate an array of chars to return.
char *buf = malloc(length);
// Copy the values from the internal array.
memcpy(buf, _dataID, length);
return buf;
}
- (void)setDataID:(const char *)dataID
{
// Copy provided chars into the internal array.
memcpy(_dataID, dataID, DATA_ID_SIZE);
// To be on the safe side, copy null character to the last element.
_dataID[DATA_ID_SIZE - 1] = '\0';
}
By the way, id is a data type in Objective-C, so it's best not to use it as a variable name.
You haven't set id anywhere, so it's just going to be nil.
Also on a side note, you must release the objects that you alloc init.
How do you want to manage the memory is the sample above? char c[size] is an array and it will take sizeof(char) * size bytes as the class member, but the property declared in the same manner will read/write pointer, not the data! I suggest you to use NSData* (or NSMutableData) instead of C-array, it's the preferred way for Obj-C.