Skip to main content

Constant Weds Literals Venue Objective C

Arrangement:

While working on a application you may have used some predefined values. The visibility of these values can be application level, feature level or class level. For the convenience we give name to these values and then use in the application. In this case the name given by you only representing the single value and it never change to represent some other value thats why it is called Constant.

On the other hand variables are like us doing jobs in IT World and can switch from one organization(value) to other.

Like while choosing a partner for marriage you may choose best for you by seeing multiple persons and still after sometime you feel stuck. Same may happen you choose a best option to declare a constant and after sometime this constant can create a issue for you in code due to its scope or any other reason. On the other hand you may have a fixed mind that you always declare a constant in a same way in any situation like a love marriage and again after sometime you feel stuck. Even if you directly use literal without declaring a constant you will definitely face problem.

Visibility of constant:

When you declare a constant you must consider the visibility of it like is it class level, application level or feature level. However it does not effect the memory usage  of the application  but from the code readability and separation of concern you must declare it by taking care of visibility. It is also good for avoiding name conflict (duplicate symbol error).

Lets check how visibility changes for constant?
There are to two storage class for this:
1) Static
2) Extern (Default)

If you declare a constant with static keyword then it can only be refer  in that particular file (Internal Linkage) and you cannot access it outside of that file. In this way the same name constant can exist in other file as well. On the other hand constant declare with extern keyword will be accessible from outside of the file(External linkage).  

Let see what clang do If I use these storage class in my code:


static NSString* sLiteralTest = @"staticConstant";
NSString* gLiteralTest = @"globalConstant";

@implementation LLVMIRTest{
    NSString* ivarTest;
}

- (instancetype) init{
    self = [super init];
    ivarTest = sLiteralTest;
    return self;
}

@end

Clang output:

//global variable reference in LLVM IR 
@gLiteralTest = global %0* bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_ to %0*), align 8

//static variable reference in LLVM IR 
@sLiteralTest = internal global %0* bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_.4 to %0*), align 8

//Ivar reference in LLVM IR 
@"OBJC_IVAR_$_LLVMIRTest.ivarTest" = hidden global i64 8, section "__DATA, __objc_ivar", align 8
@OBJC_METH_VAR_NAME_ = private global [9 x i8] c"ivarTest\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@OBJC_METH_VAR_TYPE_ = private global [12 x i8] c"@\22NSString\22\00", section "__TEXT,__objc_methtype,cstring_literals", align 1

Clang generate module corresponding to each class or file in your codebase. Above Source code is part of the module generated by clang for the class  LLVMIRTest. All the three variable is given different scope based on the linkage type specifier:

Private:
It specify that symbol is only accessible by objects in current module(class).

Internal:
It is same as private, But it treated as local symbol in module. You can directly access the symbol in the object file(static).

External(Default):
It means it is visible externally or globally. So it can refer to resolve external symbol reference.

MoreDetail:

Lets Meet the Bride (Literals):

literals are values which you directly used in source code like value of PI "3.14F",  iOS Blogs Redirect Url Value is "https://cocoainios.blogspot.in".   It can be string, Integer, Float or any other primitive data type.

Literals in memory:

Memory is one thing which you need to handle properly while doing programming or in real life as well. In both the cases it can crash your system if it is not handle properly. Let check how literal stored in memory:
There are four memory segment for a process:

1) Stack
2) Heap
3) Data
4) Code (Read only)

Which segment literal reside and for how much time?
Literals are read only and stored in binary file. So when binary is loaded in code segment the literals are also loaded. If you use Identifier to refer a literal then memory of literal is depend upon the storage class you have used. It store in data segment if static keyword or extern keyword is used. Identifier can also used code segment memory if const keyword id used.  However Identifier memory  storage section also depend upon the compiler.  

Hmmm!! That mean memory for array literal, dictionary literal are also decided at compile time ?

NSArray* literalArray = @[@"1", @"2", @"3"];
NSDictionary* literalDictionary = @{@1:@"first", @2:@"Second", @3:@"Third"};

No, Object is still store in heap and decided at run time. Let go through one by one and find out why the behaviour is different for them.

String Literals:

Almost in every programming language we are using string literals. Objective-c also support string literals with the help of class "NSConstantString". Memory for the Instance of this class is decided at compile time (statically allocate) and it occupied the memory for the full life cycle of application.

Hey! What? I have never declare any string in my code with class name "NSConstantString" then how this class come in scenario? I have always used NSString with following syntax:

NSString *myVar = @"TestString";
NSLog(@"%@", [myVar class]);

Objective-c uses abstract class feature for many of the foundation framework classes. Like NSArray,
NSDictionary etc. Same is applicable for NSString. When you declare any object with the reference name NSString then compiler will decide actual class of reference. Like in the above case it is NSConstantString string.

Let see some of the private class used by cocoa framework underneath NSString:

NSString* placeHolderString = [NSString alloc];
NSString* taggedPtrString = [[NSString alloc] initWithFormat:@"test"];
NSString* emptyString = [[NSString alloc] init];
NSMutableString* nsstring = [[NSMutableString alloc] init];
NSLog(@"%@", [placeHolderString class]); //NSPlaceholderString
NSLog(@"%@", [taggedPtrString class]); //NSTaggedPointerString
NSLog(@"%@", [emptyString class]); //__NSCFConstantString
NSLog(@"%@", [nsstring class]); //__NSCFString

Let see how it decided memory at compile time and what it store in global space?

NSConstantString class interface is following:
@interface NSSimpleCString : NSString {
@package
    char *bytes;
    int numBytes;
#if __LP64__
    int _unused;
#endif
}
@end

@interface NSConstantString : NSSimpleCString
@end

It contains only pointer to bytes and length. Compiler can easily decide the memory size and embed  the string into binary and initliaze the reference of this class with the required data.

NSString class is immutable class so in some cases compiler can do optimization and provide you the reference of constant class. Like if you allocated and init a String without any text then compiler will return you "NSCFConstantString" class reference.

Reference Handling String Literals:

1) Reference count of Const String is always -1.
2) Copy, Strong, Assign messages has same effect  in case of literals. It will return you the same memory location without reference count update.

Let see some example where your compiler return you a constant string reference behind the scene:

NSString* emptyString = [[NSString alloc] init];
NSString*  copyLiteral = [@"test" copy];
NSString* stringFromCopy = [NSString stringWithString:copyLiteral];
NSLog(@"%@", [emptyString class]);
NSLog(@"%@", [copyLiteral class]);
NSLog(@"%@", [stringFromCopy class]);
//Result is __NSCFConstantString


Some Interesting Facts About String Literals:
1) @"a" == @"a" is always true. Single memory buffer is created to store literal.
2) Sending a copy message to string literal will return you same memory address.

NSString* literal = @"test";
NSString*  copyLiteral = [literal copy];

(lldb) p literal
(__NSCFConstantString *) $2 = 0x000000010b8273e0 @"test"
(lldb) p copyLiteral
(__NSCFConstantString *) $3 = 0x000000010b8273e0 @"test"

3) It reside in code memory.
4) Even a local to function/method String literal reference remain in memory for whole application life cycle.

Numeric Literals:

There are two ways you can define numeric literals:

1) NSNumber (Boxing):

Apple introduced new syntax in LLVM 4.0 to declare a number called as Number Literals. As we know Collection classes in objective-c does not support primitive data type you need to use Wrapper NSNumber class to hold these data type. New Syntax to declare NSNumber is easier way to declare a literals:

NSNumber *numberInt = @15;
NSNumber *numberFloat = @15.6;
NSNumber *numberChar = @'a';


However these are totally different from string literals. The memory for these object is not decided at compile time and these object created in a heap. So writing the above lines in your code is equivalent to write following:

NSNumber *numberInt = [NSNumber numberWithInt:15];
NSNumber *numberFloat = [NSNumber numberWithFloat:15.6];
NSNumber *numberChar = [NSNumber numberWithChar:'a'];

So these new syntax to store scaler value is just convenience method for writing code.   

2) Inherited:

As Objective-C is superset of C so there is other way to declare numeric literals. You can directly use Primitive data type or Macro to declare numeric literals like given below:

static const int DOB = 15;
static const float vat = 14.6;
static const float initialChar = 'a';

#define DOB 15
#define vat 14.6
#define initialChar 'a'

Here in first case with const keyword we are directly using scaler type. So these are not objective-c Object and you cannot use these with collection classes.

However for memory point of view these follow the normal literals rule:
1) They always remain in memory for full application life cycle.
2) They value in stored in code segment and memory for identifier (Dob, vat, etc) against depend upon  compiler.

Note: Macro itself not exist in memory they are only known to preprocessor after that only literals value (15, 14.6,  'a') exist in code memory.

Collection Literals:

With NSNumber Literals Apple also introduced Array and dictionary literals. You can declare them by following syntax:

//Array Literal
NSArray* literalArray = @[@"1", @"2", @"3"];
    
//Dictionary Literal
NSDictionary* literalDictionary = @{@1:@"first", @2:@"Second", @3:@"Third"};

This is also a convenient method to define a collection in your code and compiler will generate actual code for you. The compiler will generate following code for the above lines:

//Array Literal
NSArray* literalArray = @[@"1", @"2", @"3"];

//Compiler Generate
id objects[] = {@"1", @"2", @"3"};
NSUInteger count = sizeof(objects) / sizeof(id);
literalArray = [NSArray arrayWithObjects:objects count:count];
    


//Dictionary Literal
NSDictionary* literalDictionary = @{@1:@"first", @2:@"Second", @3:@"Third"};
    
// Compiler generates:
id objects[] = { @"first", @"Second", @"Third"};
id keys[] = { @1,  @2, @3 };
NSUInteger count = sizeof(objects) / sizeof(id);
literalDictionary = [NSDictionary dictionaryWithObjects:objects
                                       forKeys:keys
                                         count:count];

So collection literals are also like NSNumber. They are actual array and dictionary objects and memory decided at run time.

Hmmm! That is ok But why apple did not introduced these literals like String literals?
Ok let suppose you have to introduced such literals in existing framework. First you need to create a new class to support compile time memory decision. Let support you have created NSCFConstantArray, NSCFConstantDictionary with decided structure so that the memory footprint of class can easily be decided like NSCFConstantString. That it you are done with that.

Wait ! Can these classes actually behave like dictionary and array?
No Dictionary and Array can hold other object as well like NSObject, NSNumber etc which are not compile time objects i.e you cannot decide memory of these object at compile time. So It may be the reason these collection object is not behave like constant string.

Let Move To Venue:

In objective-c there are two ways to define a constant(never change value) .
(i) Macro
(ii) Const keyword

Macro:
In Objective-C macro can be used to define a constant. However it only exist for preprocessor and compiler does not know anything about the macros. Preprocessor replace all the occurrence of macro with the given text. So it is like find and replace feature to your text editor. 

Const:
With the Const keyword you are actually declaring a variable which will exist for compiler as well as run time environment. 

Let see some of the example to declare constant:  

//Macro
#define Number_Value       @10
#define String_Value       @"test"
#define Scaler_Value       10

//Const Keyword
static const NSString* name = @"test";
static const NSUInteger dob = 10;

Ok Lets try to declare a const with NSNumber, NSDictionary or NSArray?

Ohhh! Compiler error
Reason? Lets think and add in comment section.

Which approach is better const or #define ? 

You may think that macro is good because you are saving space and time by not declaring a variable but some smart compiler also do the same thing with const. They just replace all occurrence of const with the provided text or value. 

On the other hand using const has some advantage over macro:

1) Type Checking and obey the scope principal is big advantage in case of using const. When you are declaring a variable with const keyword then you also specify the type of the identifier. So compiler can easily check if there is any type mismatch and give you warning.
2) It makes debugging easy. You can check the value at run time for the variable and debug the code. 
3) Macros are more error prone and sometime difficult to find mistake. Because compiler  do not have any reference for the Macro. Like in the following code:
  
#define DISTANCE_TRAVELLED  10.0;
#define TIME_TAKEN          2;

NSTimeInterval time = (DISTANCE_TRAVELLED / TIME_TAKEN); //Error Expected ')'


One cannot easily find out the mistake by seeing the error description. In larger codebase it can take hours to simple find out these type of error. Like duplicate definition of macro does not give you any error and you will not find out that easily.

//Abc.h
#define DOB        15

//Xyz.m
#import "abc.h"
#define DOB        10  //No error only warning depend upon compiler

Whats Next?:

Lets enjoy the food now : ). 
Yes, Try to declare a constants keeping the above points and based on your requirement use any way.   

Comments

Popular posts from this blog

What does enable bitcode do in Xcode

Background: Now days compilation process for any language is divided into two parts and same is applicable for objective c. Frontend Compiler (Clang) Backend Compiler (LLVM) Frontend Compiler (Clang):  Responsibility of front-end compiler is to take a source code and convert into intermediate representation (IR).  In case of clang it is LLVM IR.  Backend Compiler(LLVM):  Responsibility of backend compiler is to take a IR as input and convert into object code. LLVM input is bitstream of LLVM IR (Bitcode) and output is sequence of machine instruction(Object code). Each  cpu or processor has different set of  M achine   instruction, So  LLVM output is CPU dependent or it can be executed on specific CPU only.   There may be question in your mind that  1) What is the need to divide into these phases? 2) What is LLVM IR? Can we see the LLVM IR as Output? What is the need to divide into these phases? It is beneficial for both the programming language designer a

Asynchronous Request with NSOperationQueue

Today post is about how to run a asynchronous task in NSOperationQueue.  Generally we do not run a Asynchronous task in NSOperationQueue. It is also not recommended for any programmer to do that. This post is only for learning purpose what will happen if we schedule a asynchronous task in a queue and how can we complete that task:). So let us move to the learning: NSOperationQueue: In iOS NSOperationQueue is a class, which provide a way to perform operation concurrently. We also have others way to perform concurrent operation: 1) GCD 2) NSThread 3) pThread NSOperationQueue is a wrapper on GCD, which provides a very convenient way to execute operation concurrently. To create a Queue for Operation you have to simply allocate a object of the class: NSOperationQueue * opertionQueue = [[ NSOperationQueue alloc ] init ]; For this post let suppose you are making a queue to handle all Http request in your application. So i want to create a queue in Handler class

Everything about BLE with iOS Part1 (Introduction)

In this article we will learn how to turn your iPhone to behave as peripheral (who has data to send) or central (who receive the data). What is BLE (Bluetooth Low energy device) ? Bluetooth LE is a wireless personal area network technology like its previous incarnation, Classic Bluetooth. It can be use to transfer and receiving of the data. What is difference between Classic and LE ? BLE has low power consumption and low data transfer rate. BLE can support large number of slaves. On the other hand Classic (3.0) support maximum 7 devices connectivity. Unique feature of BLE is advertising  functionality,  So other devices can scan,  connect and  receive data from the advertising BLE device. Other difference is in classic you need to pair the devices first for the communication. Terms: Peripheral:  It is device which advertise the service. In client-server architecture form we can say peripheral is server which has data to send to client. The basic difference i