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

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

Shake Effect in iOS

Animation Animation always capture the user attention. We can use animation to update things on the screen.  For developer also animations fascinated things to learn and implement. Today we will try shake effect with Various  API. CABasicAnimation: Here we animate view's frame y coordinate from one position to another position. It is simple example of changing the position with respect to time. CABasic Animation is deal with the single keyframe.                                        y(t) = y 0 + t*d(y) You can use CABasic Animation if you have to play with single value. You need to move object from  one position to another without any intermediate steps. CABasicAnimation * shakeAnimation = [CABasicAnimation animationWithKeyPath: @ "position" ]; shakeAnimation . duration = 0.05 ; shakeAnimation . autoreverses = YES; shakeAnimation . repe...

NSThread with Asynchronous Request

NSThread: It is class used in Cocoa framework to create a thread.You have to specify a target and selector to create a new thread in objective c. So the selector or method is main entry point of your thread.  Detail: What happen once the thread execute all the code in the method (Thread main routine)? Thread is terminated after execute all the code in the entry(its main routine) routine. So how we can run an asynchronous request on NSThread ? What is Async request? It is non blocking request which permit the application to do other task side by side as request is in continue. So it enhance parallelism in the application. Now question is how we can prepare a asynchronous request in iOS: - ( void ) startAsyncRequestWithUrl:( NSString *)urlString{     assert (urlString != nil && urlString. length > 0 );     NSURL * url = [[ NSURL alloc ] initWithString :urlString];     NSURLRequest * urlRequest = [[ NSURLReq...