৭- অবজেক্টিভ সি (Objective C) এর প্রোটোকল ও এর ব্যবহার

Standard

আগের চ্যাপ্টারঃ অবজেক্টিভ সি (OBJECTIVE C) তে মেথড (METHOD) এর বিস্তারিত

ভূমিকাঃ
অবজেক্টিভ সি তে আপনি প্রোটোকল নামের একধরনের ফিচার ডিফাইন করতে পারবেন যেখানে কিছু মেথড ডিক্লেয়ার করা যেতে পারে যে মেথডগুলো বিশেষ পরিস্থিতিতে ব্যবহার করা যায়। যে ক্লাস ওই প্রোটোকলকে মেনে চলবে সেই ক্লাসে ওই প্রোটোকলের মেথড গুলোকে ইমপ্লিমেন্ট করা হয়।
আমরা নিচে যে উদাহরণ দেখবো সেখানে Food ক্লাসটি MakeProtocol কে মেনে চলবে, যে প্রোটোকলে processCompleted মেথডটি ডিক্লেয়ার করা আছে, যে মেথডের কাজ হচ্ছে খাবার তৈরি শেষ হয়ে গেলে ওই Food ক্লাসকে তা জানিয়ে দেয়া। অর্থাৎ, যেকোনো জায়গা থেকে Food ক্লাসের মধ্যে ইমপ্লিমেন্ট/ডিফাইন করা processCompleted মেথডকে কল করা। processCompleted মেথডটিকে অবশ্যই Food ক্লাসে ইমপ্লিমেন্ট করতে হবে। আর তাই এই ঘটনা অবশ্যই ঘটতে বাধ্য যে, Food ক্লাসের processCompleted মেথডটিকে এক্সিকিউট করা যাবেই।

সিনট্যাক্সঃ

@protocol ProtocolName
@required
// list of required methods
@optional
// list of optional methods
@end

@required কিওয়ার্ডের নিচে থাকা মেথড/মেথডগুলোকে কে অবশ্যই সেই ক্লাসে ইমপ্লিমেন্টেড থাকতে হবে যে ক্লাস এই প্রোটোকলকে মেনে চলবে (conform)। আর @optional কিওয়ার্ডের নিচে থাকা মেথড/মেথডগুলোকে কে সেই ক্লাসে ইমপ্লিমেন্ট না করলেও চলবে। নিচের মত করে একটি ক্লাস যেকোনো একটি প্রোটোকলকে মেনে চলার ব্যপারে অঙ্গীকারাবদ্ধ হতে পারে।

@interface MyClass : NSObject <MyProtocol>
...
@end

প্রোটোকল তৈরিঃ
যেকোনো প্রজেক্টে নিউ ফাইল হিসেবে প্রোটোকল ফাইলও যুক্ত করা যায়। Xcode এর File মেনু থেকে New->File ক্লিক করে নিচের মত করে একটি প্রোটোকল যুক্ত করে নিতে পারেন,
Screenshot 2014-05-25 18.53.41
তারপর সেটির নাম ঠিক করে দিতে পারেন এভাবে,
Screenshot 2014-05-25 18.56.44

প্রোটোকল এর প্রয়োগঃ
এখন আপনার প্রজেক্ট এর সাথে নিচের ফাইলগুলো মিলিয়ে একটি পরিষ্কার প্রজেক্ট সাজিয়ে ফেলুন। তারপর আমরা ওই প্রজেক্টে প্রোটোকল এর ব্যবহারটা বুঝতে চেষ্টা করব।

// MakeProtocol.h

#import <Foundation/Foundation.h>

@protocol MakeProtocol <NSObject>

- (void)processCompleted;

@end

এই আমাদের বানানো processCompleted মেথড বিশিষ্ট একটি প্রোটোকল। যে ক্লাস এই প্রোটোকলকে মেনে চলবে তাকে অবশ্যই processCompleted মেথড ইমপ্লিমেন্ট করতে হবে।

// Make.h

#import <Foundation/Foundation.h>

@interface Make : NSObject

@property (unsafe_unretained) id delegate;

- (void) startCooking;

@end

এটি হচ্ছে main এবং Food এর কর্মকাণ্ডের মধ্যবর্তী কিছু কাজের জন্য একটি ক্লাস এর ইন্টারফেস যেখানে একটি প্রোপার্টি এবং একটি মেথড ডিক্লেয়ার করা আছে। delegate প্রোপার্টিটিতে কোন ক্লাসের প্রতিনিধিত্ব সেট করা যায়। startCooking একটি সাধারণ মেথড যার বিস্তারিত একটু পরে Make এর ইমপ্লিমেন্টেশন থেকেও বোঝা যাবে।

// Make.m

#import "Make.h"
#import "MakeProtocol.h"

@implementation Make

- (void)startCooking{
    NSLog(@"Cooking Started!");
    
    // The following delegate property refers to
    // the Food class's object which was set from inside
    //// placeOrder
    // method of Food.
    
    // Then, a fact is also assured here that, the
    //// processCompleted
    // method will must be called from here which will
    // let the calling object know about its completion.
    
    [_delegate processCompleted];
}

@end

startCooking মেথডের শুরুতে আমরা একটি ম্যাসেজ প্রিন্ট করছি যে কুকিং শুরু হয়ে গেছে। তারপর আমরা এই ক্লাসের ডেলিগেট প্রোপার্টি ব্যবহার করে processCompleted ডেলিগেট মেথডকে কল করছি। এটা মূলত Food ক্লাসের মধ্যে থাকা processCompleted কেই কল করছে কারন একটু নিচেই আমরা দেখবো যে, Food ক্লাসের মধ্যের একটি মেথডের মাধ্যমে আমরা এই Make ক্লাসের ডেলিগেটটি সেট করছি অর্থাৎ Make ক্লাসের ডেলিগেট মূলত Food ক্লাসের অবজেক্ট হিসেবেই কাজ করছে।

// Food.h

#import <Foundation/Foundation.h>
#import "MakeProtocol.h"

@interface Food : NSObject <MakeProtocol>

- (void)placeOrder;

@end

উপরের কোড ব্লকে দেখতে পাচ্ছেন কিভাবে Food ক্লাসটি MakeProtocol নামের প্রোটোকলকে মেনে চলার ব্যাপারে নির্ধারিত হচ্ছে। সুপার ক্লাসের নামের পরে < MakeProtocol > এভাবে প্রোটোকল এর নাম ঠিক করে দেয়া যায়। যদি এই ক্লাসটি একাধিক প্রোটোকলকে মেনে চলতে চায় তাহলে < MakeProtocol, AnotherProtocol, … > এভাবে প্রোটোকল লিস্ট ঠিক করে দেয়া যায়। এই ক্লাসে placeOrder নামের একটি সাধারণ মেথডও আছে যেখান থেকেই আসলে খাবারের অর্ডার নিয়ে কুকিং শুরু সহ বাকি কাজগুলো হয়।

// Food.m

#import "Food.h"
#import "Make.h"

@implementation Food

- (void)placeOrder{
    Make *make = [[Make alloc]init];
    make.delegate = self;
    [make startCooking];
}

-(void)processCompleted{
    NSLog(@"Cooking Process Completed & this method has been called!");
}

@end

Food এর ইমপ্লিমেন্টেশনে প্রথমত placeOrder মেথড এর কার্যক্রম ঠিক করে দেয়া হয়েছে যেখানে বলা হয়েছে যে, প্রথমে Make ক্লাস ইন্সট্যান্সিয়েট করে সেটির ডেলিগেট প্রোপার্টি সেট করা হচ্ছে self (Food) হিসেবে। তারপর Make ক্লাসের startCooking মেথডকে কল করা হচ্ছে। আর startCooking মেথড কি করে সেটাতো একটু উপরেই বলা হয়েছে।
দ্বিতীয়ত, এখানেই Food ক্লাস বাধ্যগতভাবে processCompleted মেথডকে ইমপ্লিমেন্ট করছে। মনে করিয়ে দেই, এই মেথডটি কিন্তু Make ক্লাসের startCooking মেথডের মধ্যে থেকে কল হয় এবং আমরা বুঝতে পারি যে কুকিং কমপ্লিট হয়েছে আর এখানে সেই অনুযায়ী বাকি কাজ করি (এক্ষেত্রে কমপ্লিট হবার একটি ম্যাসেজ প্রিন্ট করছি)।
যদি এখানে (Food ক্লাসে) প্রোটোকল মেথডটিকে ইমপ্লিমেন্ট না করতাম তাহলে Xcode নিচের মত ওয়ার্নিং দিত,
Screen Shot 2014-06-02 at 9.48.46 PM

// main.m

#import <Foundation/Foundation.h>
#import "Food.h"

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {

        Food *choice = [[Food alloc] init];
        [choice placeOrder];
        
    }
    return 0;
}

বুঝতেই পারছেন, পুরো প্রোগ্রামটির শুরু এখান (main()) থেকেই। প্রথমে Food ক্লাস ইন্সট্যান্সিয়েট করা হচ্ছে। তারপর এর placeOrder মেথড কল করে অর্ডার সাবমিট করা হচ্ছে এবং পরবর্তীতে কুকিং শুরু, শেষ এবং Food ক্লাসকে জানিয়ে দেয়ার কাজ গুলো হচ্ছে যেসব উপর থেকে আমরা বর্ণনা করে এসেছি।

main থেকে শুরু করে Food, তারপর Make, মাঝখানে MakeProtocol এভাবে যদি আপনি নিজের মাথা দিয়ে কোড কম্পাইল করে করে উপরের দিকে আগান তাহলে আরেকবার পুরো উদাহরণটি বুঝতে উঠতে পারবেন বলে আশা করছি।

প্রোগ্রামটি রান করালে নিচের মত আউটপুট আসবে,
Screen Shot 2014-06-02 at 10.14.39 PM

iOS অ্যাপে প্রোটোকল এর প্রয়োগঃ
রিয়াল লাইফ iOS অ্যাপ্লিকেশন ডেভেলপমেন্টে প্রোটোকল এর ব্যবহার খুব সাধারণভাবেই চলে আসে। যেমনঃ “application delegate” অবজেক্ট সেরকম একটি ব্যাপার যেটি মূলত ওই অ্যাপ রান হওয়া থেকে শুরু করে যতক্ষণ চলবে ততক্ষণ বিভন্ন ইভেন্ট হ্যান্ডেল করে থাকে।
রিয়াল অ্যাপ ডেভেলপ করার সময় নিচের কোড ব্লক টুকু আপনার নজরে চলে আসবে,

@interface YourAppDelegate : UIResponder <UIApplicationDelegate>

যতক্ষণ পর্যন্ত এটা (আপনার “application delegate” অবজেক্ট) UIApplicationDelegate এর মধ্যে ডিফাইন করা মেথডগুলোকে রেসপন্স করবে ততক্ষণ পর্যন্ত যেকোনো অবজেক্টকেই আপনার অ্যাপ্লিকেশন ডেলিগেট হিসেবে ব্যবহার করতে পারবেন। এতে করে অ্যাপ ইভেন্ট গুলো নিয়ে কাজ করতে সুবিধা হবে।

পরের চ্যাপ্টারঃ
এই চ্যাপ্টারে আমরা প্রোটোকল নিয়ে একটি উদাহরণ এর মাধ্যমে এর ব্যবহার মোটামুটি জানতে পেরেছি। যদিও আমাদের বইয়ে আরও বিস্তারিত বিশ্লেষণ থাকবে বলে আশা করি। পরের চ্যাপ্টারে খুবি মজার এবং কাজের দুটি ফিচার অর্থাৎ অবেজক্টিভ সি এর ক্যাটাগরি (Categories) এবং ব্লক (Blocks) নিয়ে আলোচনা করা হবে।

পরের চ্যাপ্টারঃ অবজেক্টিভ-সি এর ক্যাটাগরি (CATEGORY) এবং এর বিস্তারিত

বিঃ দ্রঃ এই সিরিজের নিয়মিত পোস্টের আপডেট পেতে ব্লগে সাবস্ক্রাইব করতে পারেন

৪- অবজেক্টিভ-সি (Objective-C) তে ক্লাস ও অবজেক্ট

Standard

আগের চ্যাপ্টারঃ ৩ঃ OBJECTIVE-C তে ফাংশন ও এর ব্যবহার

ভূমিকাঃ
অন্যান্য অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং ল্যাঙ্গুয়েজের মতই অবজেক্টিভ-সি তেও – প্রোপার্টি, মেথড, ক্লাস, অবজেক্ট এই ব্যাপার গুলো বেশ ভালো ভাবেই আছে। আর এর আগে অনেক বার বলাই হয়েছে যে, সাধারণ সি ল্যাঙ্গুয়েজের সাথে অবজেক্ট ওরিয়েন্টেড ফিচার যুক্ত করেই অবজেক্টিভ-সি আত্মপ্রকাশ করেছে। এই অবজেক্ট ওরিয়েন্টেড ফিচারই মূলত সি থেকে অবজেক্টিভে-সি কে আলাদা করে। এখানেও একটি ক্লাসের মধ্যে কিছু রি-ইউজ্যাবল প্রোপার্টি-মেথড ডিফাইন করা এবং সেই ক্লাস থেকে একটি অবজেক্ট ইন্সট্যান্সিয়েট করে ওই প্রোপার্টি এবং মেথড গুলোর সাথে যোগাযোগ করার ব্যাপার গুলোও আছে।
আর অবজেক্টিভে সি কে সি++ এর সাথে তুলনা করা যায় একটি জায়গায় সেটা হল, এটা একটা ক্লাসের ইন্টারফেসকে তার ইমপ্লেমেন্টেশন থেকে পৃথক করে। ইন্টারফেস ডিফাইন করে একটি ক্লাসের পাবলিক প্রোপার্টি ও মেথড গুলোকে আর ইমপ্লেমেন্টেশন ডিফাইন করে সেগুলোর মুল কার্যক্রম বা কার্যনীতি। আগের চ্যাপ্টারের ফাংশন এর ডিক্লেয়ারেশন + ইমপ্লেমেন্টেশন = ডেফিনেশন এর মতই।

ক্লাস তৈরিঃ
এই চ্যাপ্টারে আমরা আদর্শ একটি ক্লাসের উদাহরণ হিসেবে food নামের একটি ক্লাস তৈরি করব যার ইন্টারফেস থাকবে food.h ফাইলে যেটাকে হেডারও বলা হয় আর ইমপ্লেমেন্টেশন থাকবে food.m ফাইলে। এ দুটোই Objective C ক্লাসের স্ট্যান্ডার্ড এক্সটেনশন। হেডার ফাইলের মাধ্যমে অন্য ক্লাস এই ক্লাসের সাথে যোগাযোগ করবে আর ইমপ্লেমেন্টেশন ফাইলটি মূলত কম্পাইলার এর কাছে প্রসেস হবে।

Xcode লঞ্চ করে আমাদের সেই Hello World নামক কমান্ড-লাইন টাইপ অ্যাপটাই ওপেন করুন। File -> New -> File এ গিয়ে নিচের মত করে Objective-C class সিলেক্ট করে Next করুন,
Screen Shot 2014-05-17 at 6.03.32 PM

এরপর ক্লাসের নাম হিসেবে দিন food এবং Subclass of ফিল্ডে লিখুন NSObject. নিচের ছবির মত করে। তারপর Next ক্লিক করুন। NSObject হচ্ছে অবজেক্টিভ সি এর একটি টপ লেভেল ক্লাস যাকে মোটা মুটি অন্য সবাই ইনহেরিট করে।
Screen Shot 2014-05-17 at 6.04.08 PM

শেষে Group এবং Targets ঠিক মত সিলেক্ট/চেক করা আছে কিনা দেখে নিন এবং Create বাটনে ক্লিক করুন।
Screen Shot 2014-05-17 at 6.04.26 PM

এখন আপনার প্রজেক্ট ন্যাভিগেটরে food.h এবং food.m নামের দুইটি নতুন ফাইল দেখতে পাবেন। এ দুটোই হচ্ছে আমাদের food ক্লাসের ইন্টারফেস এবং ইমপ্লেমেন্টেশন ফাইল।
Screen Shot 2014-05-17 at 6.46.43 PM

ইন্টারফেসঃ
food.h ফাইলে ক্লিক করলেই ডান পাশের এডিটরে এই ফাইলের টেম্পলেট কোড দেখতে পাবেন। আমরা এখানে একটি প্রোপার্টি এবং একটি মেথড ডিক্লেয়ার করবো। এডিট করার পর এই ফাইলের চেহারা হবে নিচের মত,

// food.h

#import <Foundation/Foundation.h>

@interface food : NSObject

@property (copy) NSString *item;

-(void)grab;

@end

@interface ডিরেক্টিভ ব্যবহার করে ইন্টারফেস তৈরি করা হয় এবং এর পরেই ক্লাসের নাম এবং তার সুপার ক্লাসের নাম একটি কোলন দিয়ে পৃথক করে লেখা হয়।
@property ডিরেক্টিভ ব্যবহার করে পাবলিক প্রোপার্টি ডিক্লেয়ার করা হয়। copy অ্যাট্রিবিউট দিয়ে এটির মেমোরি ম্যানেজমেন্ট এর ধরন বোঝানো হচ্ছে। item এ অ্যাসাইন করা ভ্যালু সরাসরি পয়েন্টার টাইপ না হয়ে কপি টাইপ হবে। সামনের চ্যাপ্টারে এ ব্যাপারে আরও বিস্তারিত থাকবে।
-(void)grab দিয়ে একটি grab নামের মেথড ডিক্লেয়ার করা হচ্ছে যার কোন প্যারামিটার নাই এবং এটা কোন কিছু রিটার্নও করে না। – সাইন দিয়ে এটা যে একটা instance method তা বোঝানো হয়। instance method এবং class method এর ব্যবহার সামনের চ্যাপ্টারে বিস্তারিত আসবে।
বিঃ দ্রঃ অনেকেই এই ইন্টারফেস ফাইলেই কিছু প্রোটেক্টেড ভেরিয়েবল ডিফাইন করে থাকেন কিন্তু এটা ভালো প্র্যাকটিস নয়। এ ব্যাপারে আমাদের একদম প্রথম অর্থাৎ সিরিজ শুরুর আগের পোস্টেও লেখা ছিল। এখানে

objective-c তে একটি ক্লাসের ইন্টারফেস সাধারণত .h ফাইল-এ লেখা হয়। অন্যদিকে .m ফাইল এর টেম্পলেট কোডেও ইন্টারফেস দেখা যায় যেটিকে মূলত বলা হয় ক্লাস এক্সটেনশন। .h ফাইলের এর ইন্টারফেসে সেই সব প্রপার্টি, মেথড ডিক্লেয়ার করা হয় যেগুলো হয়তবা অন্য ফাইল থেকেও ব্যবহার করা হতে পারে এবং যদি এমন কিছু প্রপার্টি, মেথড প্রয়োজন হয় যেগুলো শুধুই একটি .m ফাইলে ব্যবহৃত হবে অথবা প্রোটেক্টেড ভেরিয়েবল হিসেবে ব্যবহার করা হবে সেগুলোকে ক্লাস এক্সটেনশন এর মধ্যেই ডিক্লেয়ার করা ভালো অর্থাত ওই .m ফাইলের ইন্টারফেসের মধ্যে।

ইমপ্লেমেন্টেশনঃ
নিচের কোড দেখে আমরা তার নিচে এটার বিভিন্ন লাইনের বর্ণনা করবো,

// food.m

#import "food.h"

@implementation food {
    // private instance variables here
    double makingCost;
}

- (void)grab {
    NSLog(@"Eating %@ :)", self.item);
}

@end

@implementation ডিরেক্টিভ ব্যবহার করে ইমপ্লেমেন্টেশন তৈরি করা করা হয়। এখানে ইন্টারফেসের মত সুপার ক্লাসের নাম উল্লেখ করতে হয় না। এখানে একটি {} দিয়ে এর মধ্যে প্রয়োজনীয় প্রাইভেট ইন্সট্যান্স ভেরিয়েবল ডিক্লেয়ার করা হয়ে থাকে।
এরপর grab ফাংশনের কার্যক্রম ডিফাইন করা হচ্ছে অর্থাৎ এই ফাংশন কোথাও থেকে কল হলে আসলে এর প্রেক্ষিতে কি ঘটবে। self হচ্ছে এখানে Java, C++ বা PHP এর this কি-ওয়ার্ড এর মত। এটা আসলে- এই মেথড যে ইন্সট্যান্স এর মাধ্যমে কল হয় তার রেফারেন্স। এই ক্লাসে যদি payBill নামের আরও একটি মেথড ডিফাইন করা থাকতো এবং সেটিকে এখানেই কল করার দরকার হলে [self payBill] লিখে কল করা যেত।

ইন্সট্যান্সিয়েট ও ব্যবহারঃ
কোন ফাইলের যদি অন্য একটি ক্লাসের সাথে যোগাযোগের দরকার হয় তাহলে তাকে অবশ্যই ওই ক্লাসের হেডার/ইন্টারফেস ফাইল import করতে হবে। ওই ক্লাসের ইমপ্লেমেন্টেশন ফাইলকে সরাসরি এক্সেস করা উচিত হবে না। তা নাহলে এই যে, ইন্টারফেসের মাধ্যমে ইমপ্লেমেন্টেশন থেকে পাবলিক API আলাদা করে কাজ করার নিয়ম, এটাই ভেস্তে যাবে। তো, এখন আমরা আমাদের main.m ফাইল থেকে এই ক্লাসের সাথে কাজ করব। এর জন্য নিচের মত করে main.m ফাইলকে আপডেট করতে হবে,

// main.m

#import <Foundation/Foundation.h>
#import "food.h"

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {

        food *pizza = [[food alloc] init];
        
        // accessing value using accessor methods aka getter/setter
        [pizza setItem:@"Italian Pizza"];
        NSLog(@"Ordered a %@", [pizza item]);
        
        // accessing value using dot syntax
        pizza.item = @"Mexican Pizza";
        NSLog(@"Changed the item to a %@", pizza.item);
        
        [pizza grab];
        
    }
    return 0;
}

৪ নাম্বার লাইনে ইটারফেস import করার পর মেইন ফাংশনের মধ্যে থেকে food ক্লাসের অবজেক্ট ইন্সট্যন্সিয়েট করা হয়েছে alloc init প্যাটার্ন এর মধ্যমে। অজেক্টিভ-সি তে একটি অবজেক্ট ইন্সট্যন্সিয়েট করা দুই ধাপে সম্পন্ন হয়। প্রথমে অবজেক্টটির জন্য কিছু মেমোরি অ্যালোকেট করে নেয়া হয় alloc নামের বিল্টইন মেথডের মাধ্যমে তারপর সেটিকে ইনিশিয়ালাইজ করা হয়। আর অবজেক্টটিকে একটি পয়েন্টার হিসেবে স্টোর করা হয় কারন ইতোমধ্যে অনেকবারই বলা হয়েছে যে অবজেক্টিভ-সি তে সব রকম অবজেক্টকেই পয়েন্টার হিসেবে স্টোর করতে হয়। আর তাই food pizza = … না লিখে food *pizza = … লেখা হয়েছে। এখানে food হচ্ছে যে ক্লাসের অবজেক্ট বানাতে চান তার নাম এবং pizza হচ্ছে অবজেক্টের নাম।
এর পরেই এই অবজেক্টের প্রোপার্টি সেট করা হয়েছে item ভ্যারিয়েবলের accessor method (গেটার/সেটার) ব্যবহার করে যেটা স্বয়ংক্রিয় ভাবেই হয়ে যায় Xcode 5 এ। এর আগে এই ভ্যারিয়েবলকে @synthesize করে এর জন্য (গেটার/সেটার) জেনারেট করতে হত। গেটার হিসেবে শুধুমাত্র ভ্যারিয়েবলটির নাম ব্যবহার করলেই হবে এবং সেটার হিসেবে ভ্যারিয়েবলটির প্রথম অক্ষরকে বড় হাতের করে এবং সামনে set বসিয়ে দিয়ে এক্সেস করলেই হবে। যা করা হয়েছে উপরের ১৪, ১৫ নাম্বার লাইনে। ১৪ নাম্বারে ভ্যালু সেট করা হয়েছে এবং ১৫ নাম্বারে ভ্যালু চেয়ে নেয়া হয়েছে।
আবার, dot syntax ব্যবহার করেও এই অবজেক্টের প্রোপার্টি গুলোকে কিভাবে এক্সেস করা যেতে পারে তা দেখানো হয়েছে ১৮ এবং ১৯ নাম্বার লাইনে।
এরপরে ২১ নাম্বার লাইনে [রিসিভার ম্যাসেজ] প্যাটার্ন মোতাবেক food অবজেক্টের grab মেথডকে কল করা হয়েছে।
আর আলোচ্য অংশে যে, [ ] এর ব্যবহার সেটাকে অবজেক্টিভ-সি স্টাইল মনে করেই আগাতে পারেন। Command+R চেপে এই অ্যাপকে রান করালে এর আউটপুট নিচের মতই আসবে এবং সেটা অ্যানালাইসিস করলেই বুঝতে পারবেন আপনি অবজেক্ট অরিয়েন্টেশনে ঢুকে পরেছেন।
Screen Shot 2014-05-17 at 7.54.44 PM

ক্লাস মেথড ও ক্লাস ভেরিয়েবলঃ
উপরের উদাহরণে ইন্সট্যান্স লেভেলের প্রোপার্টি ও মেথড নিয়ে কাজ করা হয়েছে। অর্থাৎ প্রথমে একটি ক্লাসের অবজেক্ট তৈরি করা হয়েছে এবং সেই অবজেক্টকে ধরেই ওই ক্লাসের প্রোপার্টি ও মেথড এর সাথে যোগাযোগ করা হয়েছে। অব্জেক্টিভ-সি তে ক্লাস লেভেল প্রোপার্টি ও মেথডও আছে।
এর ডিক্লেয়ারেশনও ইন্সট্যান্স লেভেল মেথড এর মতই কিন্তু শুরুতে – সাইনের বদলে + সাইন দেয়া হয়। যেমন নিচে একটি ক্লাস লেভেল মেথড ডিক্লেয়ার করা হয়েছে, স্বভাবতই হেডার ফাইলে। উল্লেখ্য, এই নতুন মেথডটি কিন্তু একটি NSString টাইপের প্যারামিটার নেয় কিন্তু কিছু রিটার্ন করে না।

// food.h

#import <Foundation/Foundation.h>

@interface food : NSObject

@property (copy) NSString *item;

-(void)grab;
+ (void)setDefaultItem:(NSString *)item;

@end

আর এই ধরনের মেথডের ইমপ্লেমেন্টেশনও একই রকম ভাবে করা হয়। নিচে দুইটি কাজ একসাথে করা হয়েছে প্রথমত একটি ক্লাস লেভেল মেথডের ইমপ্লেমেন্টেশন লেখা হয়েছে এবং দ্বিতীয়ত সেই মেথডের মাধ্যমে একটি স্ট্যাটিক ভ্যারিয়েবলের ভ্যালু সেট করা হয়েছে যেহেতু অব্জেক্টিভ-সি তে ক্লাস লেভেল ভ্যারিয়েবল বলে কিছু নাই। অর্থাৎ defaultItem কে আমরা অন্য কোথাও থেকে ক্লাস লেভেল ভ্যারিয়েবল হিসেবে এক্সেস করতে পারবো না যেমন ভাবে setDefaultItem মেথড কে ক্লাস লেভেল মেথড হিসেবে এক্সেস করতে পারবো।

// food.m

#import "food.h"

static NSString *defaultItem;


@implementation food {
    // private instance variables here
    double makingCost;
}

- (void)grab {
    NSLog(@"Eating %@ with an obvious %@:)", self.item, defaultItem);
}

+ (void)setDefaultItem:(NSString *)item {
    defaultItem = [item copy];
}

@end

এখন main.m ফাইল থেকে আমরা নিচের মত করে এই ক্লাস লেভেল মেথডটিকে এক্সেস করতে পারি (১১ নাম্বার লাইনে সরাসরি ক্লাসের নাম দিয়েই ওটার একটি মেথড setDefaultItem কে ধরা যাচ্ছে) যেটা কিনা এর কাছে পাঠানো একটি স্ট্রিংকে ওই ক্লাসের একটি স্ট্যাটিক ভ্যারিয়েবলের ভ্যালু হিসেবে সেট করে। তারপর আমরা আগের উদাহরণে যা করেছিলাম ঠিক সেই কাজ আবার করেছি।

// main.m

#import <Foundation/Foundation.h>
#import "food.h"

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {
        
        [food setDefaultItem:@"Lemonade"];

        food *pizza = [[food alloc] init];
        
        // accessing value using accessor methods aka getter/setter
        [pizza setItem:@"Italian Pizza"];
        NSLog(@"Ordered a %@", [pizza item]);
        
        // accessing value using dot syntax
        pizza.item = @"Mexican Pizza";
        NSLog(@"Changed the item to a %@", pizza.item);
        
        [pizza grab];
        
    }
    return 0;
}

কিন্তু এবার grab মেথড জানাচ্ছে যে, আপনি একটা পিৎজা খাচ্ছেন কিন্তু সাথে আপনার একটা কমন পছন্দের আইটেম আছে লেমোনেড।
Screen Shot 2014-05-17 at 8.35.57 PM

কন্সট্রাক্টরঃ
অবজেক্টিভ-সি তে সরাসরি কোন কন্সট্রাক্টর মেথড নাই। তবে অন্যান্য ল্যাঙ্গুয়েজের বিল্টইন কন্সট্রাক্টর মেথড যা করে (ক্লাস থেকে অবজেক্ট ইন্সট্যান্সিয়েট করার সময়ই কিছু সাধারণ কাজ করে ফেলা) ঠিক তাই করা যাবে নিচের পদ্ধতি অনুযায়ী।
অবজেক্টিভ-সি তে একটি অবজেক্ট অ্যালোকেটেড হবার পর পরই init মেথড কল করার মাধ্যমে সেটি ইনিশিলাইজ হয়। যেমন উপরের উদাহরণে food *pizza = [[food alloc] init] লাইনে। আবার ক্লাস লেভেল ইনিশিলাইজেশনও আছে সেটা পরে দেখা যাবে। আগে এই পদ্ধতিতে কন্সট্রাকশন এর কাজ করি।
init হচ্ছে একটি ডিফল্ট ইনিশিলাইজেশন মেথড। কিন্তু আপনি নিজেও আপনার মত করে একটা ইনিশিলাইজেশন মেথড তৈরি করতে পারেন। এটা খুব একটা কঠিন কাজ না, শুধু নরমাল টাইপের একটা মেথডের নামের আগে init শব্দটা ব্যবহার করতে হবে। নিচে আমরা সেরকম একটি ডিক্লেয়ার করেছি food.h ফাইলে যার নাম initWithItem,

// food.h

#import <Foundation/Foundation.h>

@interface food : NSObject

@property (copy) NSString *item;

-(void)grab;
-(id)initWithItem:(NSString *)item;

@end

এখন এই কাস্টম ইনিশিলাইজার এর ইমপ্লেমেন্টেশন করতে হবে নিচের মত করে,

// food.m

#import "food.h"
#import "food.h"

@implementation food {

}

- (void)grab {
    NSLog(@"Eating %@ :)", self.item);
}

- (id)initWithItem:(NSString *)item {
    self = [super init];
    if (self) {
        _item = [item copy];
    }
    return self;
}

@end

এখানে super, প্যারেন্ট ক্লাসকে নির্দেশ করে এবং self হচ্ছে সেই ইন্সট্যান্সকে/অবজেক্টকে নির্দেশ করে যেটা এই মেথডটিকে কল করে। ইনিশিলাইজার মেথডকে সবসময় ওই অবজেক্টের কাছে নিজের রেফারেন্সটাই রিটার্ন করতে হয়। আর তাই, এই মেথডের মধ্যে অন্যান্য কাজ করার আগে চেক করে নিতে হয় self আছে কিনা। তারপর আমরা ডাইরেক্ট _item = … ব্যবহার করে এই ইন্সট্যান্স ভ্যারিয়েবলের ভ্যালু সেট করে দিলাম এই মেথডের সাথে আসা প্যারামিটার এর কন্টেন্টকে কপি করে।
অর্থাৎ যখনই initWithItem ব্যবহার করে এই ক্লাস এর অবজেক্ট ইন্সট্যান্সিয়েট করা হচ্ছে ঠিক তখনই এই ক্লাসের একটি প্রোপার্টির ভ্যালু আমরা আসাইন করে দিচ্ছি। ঠিক এটাই সহজ ভাবে যেকোনো কন্সট্রাক্টর মেথডের কাজ। এখন এটা টেস্ট করার জন্য main.m ফাইলটিকে নিচের মত করে পরিবর্তন করে নিতে পারেন,

// main.m

#import <Foundation/Foundation.h>
#import "food.h"

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {

        food *choice = [[food alloc] initWithItem:@"Pan Pizza"];

        [choice grab];
        
    }
    return 0;
}

উপরের কোড ব্লক লক্ষ্য করলে দেখবেন যে, food ক্লাসের অবজেক্ট choice কে ইনিশিয়ালাইজ করা হয়েছে initWithItem নামক কাস্টম ইনিশিয়ালাইজার মেথড দিয়ে। আর এই initWithItem মেথড food ক্লাসের একটি প্রোপার্টি যার নাম item সেটার ভ্যালু সেট করে দেয়। আর তাই, অবজেক্ট ইনিশিয়ালিয়াজেশনের পর পরই যদি আমরা grab মেথড কল করি যেটা কিনা কনসোলে ওই আইটেমটা খাওয়ার কথাটাই প্রিন্ট করার কথা – তাহলে নিচের মত ঠিক ঠাক আউটপুট আসে।
Screen Shot 2014-05-18 at 3.27.30 AM

পরের চ্যাপ্টারঃ
প্রোপার্টি ( @property ) নিয়ে বিস্তারিত আলোচনা এবং বিভিন্ন অ্যাট্রিবিউট সাথে এর সম্পর্ক নিয়ে কিছু উদাহরণ এবং আলোচনা থাকবে।

পরের চ্যাপ্টারঃ অবজেকটিভ সি (OBJECTIVE C) তে প্রোপার্টি ও এর অ্যাট্রিবিউটের ব্যবহার

৩- অবজেক্টিভ-সি (Objective-C) তে ফাংশন ও এর ব্যবহার

Standard

আগের চ্যাপ্টারঃ ২ঃ OBJECTIVE-C এর ভিতরে আমাদের প্রিয় C

ভূমিকাঃ
গত অধ্যায়ে Objective-C এর সাথে C এর সম্পর্ক এবং C তে কমেন্ট, ভ্যারিয়েবল, কন্সট্যান্ট, অ্যারিদম্যাটিক অপারেশন, কন্ডিশনাল অপারেশন, লুপ, ম্যাক্রো, স্ট্রাকচার, ইনিওমেরেশন, অ্যারে, পয়েন্টার ইত্যাদির ব্যবহার শিখেছি যা C এবং OBjective-C তথা সকল প্রোগ্রামিং ল্যাঙ্গুয়েজের অতি সাধারণ কিছু ফিচার। ফাংশনও এদের মতই আর একটি বিষয় যা সকল আধুনিক প্রোগ্রামিং ল্যাঙ্গুয়েজের একটি সাধারণ ফিচার বা কম্পোনেন্ট।

কি এবং কেন?
ফাংশন নির্দিষ্ট কোড ব্লককে সম্পুর্ন অ্যাপ্লিকেশনে রিইউজ করার সুবিধা দেয়। ধরি, আমি খুব ভোজন রসিক এবং নিজেই নতুন নতুন রান্না করে খেতেই বেশি পছন্দ করি। একারনে আমি একেকবার একেক জনের কাছ থেকে বিভিন্ন খাবারের রেসিপি জেনে নেই।
এবার ধরি, আমি একজন নির্দিষ্ট বাবুর্চি চিনে রাখলাম যার কাজ হবে আমাকে রেসিপি জানানো। সে যেখানেই থাকুক না কেন আমি তাকে ফোন করে খাবারের নাম বলব এবং সে আমাকে রেসিপিটা জানাবে। এখন কিন্তু একেক বার একেক লোকের সাহায্য লাগবে না আমার। একজনই থাকবে, আমার যখন দরকার পরবে, তখন সেই একজনকেই আমি ব্যবহার করব। এই নির্দিষ্ট একজন লোকই প্রোগ্রামিং এর ভাষায় ফাংশন
আমরা আমাদের সাধারণ এবং সবসময় যেগুলো লাগে সেই কাজ গুলোকে কিছু স্বাধীন ভাগে ভাগ করব এবং সেই একেক ভাগকে আলাদা আলাদা ফাংশন হিসেবে ডিফাইন (কার্যকলাপ নির্ধারণ করে দেয়া) করব। তাহলে একই কাজের জন্য বার বার কোড লিখতে হবে না। শুধু ওই ফাংশনকে ডাকলেই (ফাংশন কল) হবে।

ফাংশনের ব্যাসিক সিন্ট্যাক্সঃ
একটি ফাংশনের মোট চারটি অংশ থাকে-

  • রিটার্ন ভ্যালু (এই ফাংশনটি কাজ শেষে যদি কোন কিছু ফেরত/ফলাফল দেয় তাহলে সেটির ডাটাটাইপ কি হবে)
  • নাম (ফাংশনটির একটি নির্দিষ্ট নাম থাকবে যা দিয়ে তাকে ডাকা হবে বার বার)
  • প্যারামিটারস (ফাংশনটির কাজ সম্পুর্ন করতে যদি তথ্যের দরকার পরে তাহলে সেই তথ্য গুলো)
  • কোড ব্লক (এই অংশে ফাংশনটা যে কাজ করবে তার প্রোগ্রাম্যাটিকাল কোড/লজিক থাকে)

উদাহরন স্বরুপ নিচের কোডটুকু দেখা যাক,

#import <Foundation/Foundation.h>

void billKotoHolo()
{
    NSLog(@"স্যার আপনার বিল হয়েছে ১২০০ টাকা");
}


int main(int argc, const char * argv[])
{

    @autoreleasepool {
        billKotoHolo();
    }
    return 0;
}

এখানে দেখা যাচ্ছে billKotoHolo() একটা ফাংশন। মেইন main() ফাংশন এর মধ্যে থেকে একে কল করা হয়েছে। এই ফাংশনটি মেইন ফাংশনকে কোন কিছু রিটার্ন করবে না তাই এর রিটার্ন টাইপ void। এই ফাংশনের কার্যকলাপ বলতে গেলে সিমপ্লি কনসোলে একটা ম্যাসেজ প্রিন্ট করা আর এই কাজটুকু করতে এর কোন প্যারামিটার দরকার নাই। তাই ডেফিনেশন এর সময় () এর মধ্যে কিছু নাই। {} এর ভিতরের অংশই কোডব্লক যেখানে বলা আছে এই ফাংশনের কাজ কি। আবার, কল করার সময়ও কোন প্যারামিটার পাঠানো হয়নি তাই () ব্র্যাকেটের ভিতরের অংশ ফাকা। অর্থাৎ কোন প্যারামিটার পাস করা হচ্ছে না।

ফাংশনে, পয়েন্টার রেফারেন্সকেও রিটার্ন ভ্যালু এবং প্যারামিটার হিসেবে ব্যবহার করা যায়। অর্থাৎ ফাংশন গুলো খুব সহজেই Objective-C এর অবজেক্ট গুলোর সাথে ব্যবহৃত হতে পারে। কারন, আগেই বলা হয়েছে যে, “Objective-C তে সব ধরনের অবজেক্টকে পয়েন্টার হিসেবে প্রকাশ করা হয়/যায়।” এখন নিচের উদাহরণটা খেয়াল করুন,

#import <Foundation/Foundation.h>

int getCount(NSArray *foods) {
    int count = (int)[foods count];
    return count;
}

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        NSArray *foods = @[@"Chicken Fry", @"Soup", @"Biriani", @"Snacks"];
        NSLog(@"%d", getCount(foods));    }
    return 0;
}

getCount() ফাংশনটি আর্গুমেন্ট হিসেবে NSArray অবজেক্ট (Objective-C তে একটি অ্যারেটাইপ ভ্যারিয়েবল যাতে আমরা রেষ্টুরেন্টের খাবারের লিস্ট রাখছি) নেয় এবং integer টাইপ ডাটা (মোট আইটেমের সংখ্যা) রিটার্ন করে।

int count = (int)[foods count];

এই লাইন টি দেখে ঘাবড়ানোর কিছু নেই। foods অ্যারেতে কতগুলো ইলিমেন্ট আছে সে সংখ্যাটি count রিটার্ন করে। count হচ্ছে food অবজেক্টের একটি বিল্ট-ইন মেথড যেটা আসলে NSArray ক্লাসে ডিফাইন করা আছে। পরবর্তীতে বিস্তারিত দেখানো হবে।

ডিক্লেয়ারেশন বনাম ইম্প্লিমেন্টেশনঃ
যেখানে একটি ফাংশনকে কল করে ব্যবহার করা হবে তার পুর্বেই কোথাও ফাংশনটিকে ডিফাইন করতে হয়। অর্থাৎ ব্যবহারের পুর্বেই কম্পাইলার কে জানাতে হবে যে getCount() নামে একটি ফাংশন আছে এবং এই ফাংশনটির কাজের বর্ণনা তথা ডেফিনিশন/ইম্প্লিমেন্টেশনও ঠিক করা আছে। উপরের কোড এ getCount() ফাংশনটি main() এর আগে না লিখে পরে লিখে main() এর ভিতর থেকে কল করলে কম্পাইলার ফাংশনটিকে খুজে পেত না।

ফাংশনের ডিক্লেয়ারেশন কম্পাইলারকে ফাংশনটির ইনপুট, আউটপুট সম্পর্কে জানায়। শুধুমাত্র রিটার্ন ডাটার ডাটাটাইপ ও প্যারামিটারস পাঠিয়ে কম্পাইলার চেক করতে পারে যে ফাংশনটির ব্যবহার ঠিকমত হচ্ছে কিনা। উদাহরনস্বরুপ বলা যায়, ডিক্লেয়ারেশন এ রিটার্ন টাইপ হিসেবে ঠিক করা আছে int কিন্তু আসলে কোডব্লক এ ডাটা পাঠাচ্ছে double, তাহলে কম্পাইলার এই ভুলটা ধরতে পারে। এই ডিক্লেয়ারেশন এর সাথে একটি কোডব্লক (ইমপ্লিমেন্টেশন) এটাচ করলেই তা হয়ে যায় সম্পুর্ন ডেফিনিশন।
নিচের কোডটি দেখলেই ব্যপারটি পরিস্কার হয়ে যাবে,

// main.m
#import <Foundation/Foundation.h>

// Declaration
int getCount(NSArray *);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSArray *foods = @[@"Chicken Fry", @"Soup", @"Hydrabadi Biriani", @"Snacks"];
        NSLog(@"%d", getCount(foods));
    }
    return 0;
}

// Implementation
int getCount(NSArray *foods) {
    int count = (int)[foods count];
    return count;
}

এখানে আগে ফাংশনটিকে ডিক্লেয়ার করা হয়েছে এবং এটার ব্যাপারে কম্পাইলারকে জানানো হচ্ছে এবং পরে যেকোনো এক জায়গায় সেটার পূর্ণ ইমপ্লিমেন্টেশন লেখা হয়েছে।
উল্লেখ্য, রিটার্ন টাইপে সকল ধরনের বেসিক ডাটাটাইপ, পয়েন্টার ও অবজেক্ট হতে পারে। কিন্তু খেয়াল রাখতে হবে যে, ফাংশন শুধু মাত্র একটি ইনফরমেশনই রিটার্ন করতে পারে। হতে পারে সেটি একটি অবজেক্ট অথবা একটি অ্যারে অথবা একটি পয়েন্টার অথবা অন্য যেকোন ডাটাটাইপ।

ফাংশন ওভারলোডিংঃ
C এর মত Objective-C তেও ফাংশন ওভারলোডিং নাই। আসলে অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং এর প্রধান যে ৩ টি ফিচার আছে তার মধ্যে একটি হল পলিমরফিজম। ফাংশন ওভারলোডিং পলিমরফিজম এরই উদাহরন। পরবর্তীতে অধ্যায় গুলো এ সম্পর্কে বিস্তারিত আলোচনা হবে। নিচের উদাহরনটি দেখলেই বুঝা যাবে।
Screen Shot 2014-05-09 at 10.40.28 PM

Static কি-ওয়ার্ড ঃ
Static কি-ওয়ার্ডটি ফাংশন অথবা ভ্যারিয়েবল এর অ্যাভেইলাবিলিটি (Availibility) অল্টার করার সুবিধা দেয়। মুলত এই কিওয়ার্ডের এফেক্ট নির্ভর করে কোন ক্ষেত্রে এর ব্যবহার হচ্ছে তার ওপর। Static কিওয়ার্ডটি ফাংশন অথবা ভ্যারিয়েবল ডিক্লারেশন এ ব্যবহার করা হয়। এই অংশে স্ট্যাটিক কিওয়ার্ডের ব্যবহার দেখানো হবে।

স্ট্যাটিক ফাংশন (Static Function)ঃ
স্বাভাবিকভাবেই সকল ফাংশনই গ্লোবাল স্কোপে থাকে। এ কথার মানে হল কোন ফাইলে ফাংশন ডিফাইন করার সাথে সাথে তা অন্য সকল ফাইল থেকে কল করা যায় যদি ওই ফাংশন ওয়ালা ফাইলটি কলার (caller) ফাইলে ইনক্লুড করে নেয়া হয়। ধরে নেই আমাদের প্রজেক্টে ৩ টা ফাইল আছে। কোন একটি ফাইলে যদি কোন ফাংশনের ডেফিনেশন থাকে তাহলে অন্য সকল ফাইল থেকে এই ফাংশন কে ব্যবহার করা যাবে। যদি আমরা চাই যে এই ফাংশনটি শুধুমাত্র এই ফাইল থেকেই ব্যবহার করা যাবে, অর্থাৎ এই ফাংশনটি এই ফাইলের প্রাইভেট ফাংশন হবে তাহলে ফাংশনটিকে স্ট্যাটিক হিসেবে ডিক্লেয়ার করলেই কাজটি হয়ে যাবে। বিভিন্ন ফাইলে যদি একই নামের ফাংশন থাকে তারপর ও কনফ্লিক্ট করবে না।

স্ট্যটিক ফাংশনের বেসিক সিনট্যাক্স নিচের উদাহরনে দেখানো হল। এই কোডটুকু যদি অন্য কোন ফাইলে লিখা হয় যেমন কোন ফাংশন লাইব্রেরীতে, তাহলে কখনোই main.m এর মধ্যে থেকে getRestaurantMenu() ফাংশনটিকে এক্সেস/কল করা যাবে না।

// Static function declaration
static NSArray getRestaurantMenu();

// Static function implementation
static int getRestaurantMenu() {
    NSArray *menuList = @[@"Chicken Fry", @"Soup", @"Biriani", @"Snacks"];
    return (int)[menuList count];
}

বিশেষভাবে উল্লেখ্য যে, static কিওয়ার্ডটি ডিক্লারেশন এবং ইমপ্লিমেন্টেশন উভয় ক্ষেত্রেই ব্যবহার করতে হবে।

স্ট্যাটিক লোকাল ভ্যারিয়েবলঃ
কোন ফাংশনের ভেতরে ডিক্লেয়ার করা ভ্যারিয়েবল কে ওই ফাংশনের লোকাল ভ্যারিয়েবল বলা হয়। অর্থাৎ ভ্যারিয়েবলটির স্কোপ হবে ওই ফাংশনের ভেতরের অংশটুকুই। যতবার এই ফাংশনটি কল করা হবে ততবারই ভ্যারিয়েবলটি নতুন করে রি-সেট হবে। “নতুন করে রি- সেট” হওয়া বলতে বোঝানো হচ্ছে যে, আগের বার কল হওয়ার সময় ভ্যারিয়েবলটির আপডেটেড ভ্যালু, মেমোরি লোকেশন পরেরবারের সাথে মিলবে না। প্রত্যেক বার ফাংশনটি কল হবার সময় ভ্যারিয়েবলটির নতুন করে মেমোরি লোকেশন সেট হবে এবং সেটির প্রাথমিক ইনিসিয়ালাইজড মান সেট হবে, তথা রিসেট হবে।

#import <Foundation/Foundation.h>

int getNumberOfChicken()
{
    int count = 0;
    count = count + 1;
    return count; 
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog( @"%d", getNumberOfChicken());   // 1
        NSLog( @"%d", getNumberOfChicken());   // 1     
    }
    return 0;
}

উপরের কোডে getNumberOfChicken() ফাংশনটিতে count ভ্যারিয়েবলটি স্ট্যাটিক না। তাই যতবারই main() থেকে getNumberOfChicken() কে কল করা হবে, ততবারই নতুন করে count ডিক্লেয়ার হবে (নতুন মেমরী লোকেশন এবং ভ্যালু ০)।

কিন্তু নিচের মত করে, এই ভ্যারিয়েবলটি ডিক্লেয়ার করার সময় যদি স্ট্যাটিক হিসেবে ডিক্লেয়ার করা হয় তাহলে প্রত্যেকবার কল হওয়ার সময় নতুন করে রি-সেট হবে না। আগের বার ফাংশনটি এক্জিকিউট হওয়ার পর ভ্যারিয়েবলটির যা ভ্যালু ছিল তাই থাকবে কারন মেমরী লোকেশন আগেরটাই থাকবে।

#import <Foundation/Foundation.h>

int getNumberOfChicken()
{
    static int count = 0;
    count = count + 1;
    return count; 
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog( @"%d", getNumberOfChicken());   // 1
        NSLog( @"%d", getNumberOfChicken());   // 2     
    }
    return 0;
}

ভ্যারিয়েবলটি static হিসেবে ডিক্লেয়ার করার কারনে শুধুমাত্র প্রথমবার count ভ্যারিয়েবলের জন্য মেমরী লোকেশন সেট হয় এবং ০ দিয়ে ইনিশিয়ালাইজ হয়। কিন্তু পরবর্তীতে যতবারই কল করা হোক না কেন count এর ভ্যালু ওই মেমরী লোকেশন থেকেই ইনভোক করা হয়।

ফাংশনের স্ট্যাটিক লোকাল ভ্যারিয়েবল গুলো যতবারই কল করা হোক না কেন, সাধারন লোকাল ভ্যারিয়েবলের মত বার বার ওই ভ্যারিয়েবল রিসেট হয় না। ফাংশন ওই ভ্যারিয়েবল শেষ অবস্থার ডাটা মনে রাখে। কিন্তু স্ট্যাটিক ফাংশনের মত স্ট্যাটিক লোকাল ভ্যারিয়বলের স্কোপের কোন পরিবর্তন হয় না। স্ট্যাটিক লোকাল ভ্যারিয়েবল শুধু মাত্র ওই ফাংশনের স্কোপেই ব্যবহার করা যাবে।

ফাংশন লাইব্রেরীঃ
অবজেক্টিভ-সি নেমস্পেস সাপোর্ট করে না। অন্যান্য গ্লোবাল ফাংশন গুলোর সাথে যাতে নাম নিয়ে কোন কনফ্লিক্ট না হয় সে জন্য ফাংশন এবং ক্লাসগুলোতে ইউনিক আইডেন্টিফায়ার হিসেবে প্রিফিক্স যোগ করে দেওয়া হয়। ফলস্বরুপ শুধু CaptureSession এর পরিবর্তে AVCaptureSession(), শুধু Layer এর পরিবর্তে CALayer() ইত্যাদি ফাংশন দেখা যায়।

তাই আমরা যখন নিজেদের লাইব্রেরী বানাবো তখন ফাংশনের নাম গুলো একটা হেডার (.h) ফাইলে ডিক্লেয়ার করব এবং আলাদা ইমপ্লিমেন্টেশন (.m) ফাইলে ফাংশনগুলোর ইমপ্লিমেন্টেশন করব। Objectiv-C এর ক্লাস গুলোর গঠনও এরকম। এই পদ্ধতিতে ফাইল দুটোকে যথাক্রমে ইন্টারফেস ফাইল এবং ইমপ্লিমেন্টেশন ফাইল বলা হয়। এতে করে ওই লাইব্রেরী ব্যবহার করার সময় ইমপ্লিমেন্টেশন না ভেবে শুধুমাত্র হেডার ফাইলকে ইমপোর্ট করেই কাজ করা যাবে।
উল্লেখ্য, হেডার ফাইলের এই ধরনের ব্যবহারকে একটা API লেয়ার হিসেবেও কল্পনা করা যায়। অর্থাৎ আমরা আরেকটা ক্লাসের সাথে যোগাযোগের জন্য সেটার এক্সেস-অ্যাবল লেয়ার তথা ইন্টারফেস ফাইলের সাথে যোগাযোগ করবো, মুল ইমপ্লেমেন্টেশন ফাইলের সাথে নয়।

//  RestaurantUtilities.h
#import <Foundation/Foundation.h>

NSString *RUgetRestaurantTitle();
int RUgetCountOfItems();

এই হেডার ফাইলের ইম্পলিমেন্টেশন ফাইলটি নিচের মত হতে পারে,

//  RestaurantUtilities.m
#import "RestaurantUtilities.h"

NSString *RUgetRestaurantTitle()
{
    return @"ভুতের আড্ডা";
}

int RUgetCountOfItems()
{
    NSArray *items = @[@"সরষে ইলিশ", @"খিচুরী"];
    return (int)[items count];
}

এখন main.m এ RestaurantUtilities.h হেডার ফাইল কে ইমপোর্ট করে সকল ফাংশনগুলোকে ব্যবহার করতে পারবো। এখানে উল্লেখযোগ্য যে RestaurantUtilities.m এ যদি কোন static ফাংশনের ডিক্লারেশন এবং ইমপ্লিমেন্টেশন থেকে থাকত তাহলে কিন্তু main.m থেকে সেই ফাংশনগুলো ব্যবহার করতে চাইলে কম্পাইলার এরর হবে, যার ব্যাখ্যা আগেই দেয়া হয়েছে।

//  main.m
#import <Foundation/Foundation.h>
#import "RestaurantUtilities.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
    
        NSLog( getRestaurantTitle());     // ভুতের আড্ডা
        NSLog( @"%d", getCountOfItems()); // 2 
        
    }
    return 0;
}

পরের চ্যাপ্টারঃ
এই চ্যাপ্টারে C এবং Objective-C তে ফাংশনের ব্যবহার, সাথে এদের এবং ভেরিয়েবলের স্কোপ, ডিক্লেয়ারেশন, ইমপ্লেমেন্টেশন, ইন্টারফেস/হেডার ফাইল, ইমপ্লেমেন্টেশন ফাইল ইত্যাদি বিষয় নিয়ে আলোচনা হয়েছে। পরবর্তী চ্যাপ্টারে আমরা Objective-C এর অবজেক্ট ওরিয়েন্টেড ফিচার নিয়ে বিস্তারিত আলোচনা করবো। সেখানে থাকবে কিভাবে ক্লাস ডিফাইন করা যায়, কিভাবে অবজেক্ট ইন্সট্যান্সিয়েট করা যায়, কিভাবে প্রোপার্টি সেট করা যায় এবং কিভাবে মেথড কল করা যায় ইত্যাদি।

পরের চ্যাপ্টারঃ ৪ঃ অবজেক্টিভ-সি (Objective-C) তে ক্লাস ও অবজেক্ট

২- Objective-C এর ভিতরে আমাদের প্রিয় C

Standard

আগের চ্যাপ্টার – ১ঃ OBJECTIVE-C প্রাথমিক ধারনা এবং XCODE

ভূমিকাঃ
টাইটেল দেখে যদি আপনার মনে এই ধারনা হয়ে থাকে যে, “Objective-C এর মধ্যে কি C ব্যবহার করা যাবে?” অথবা “Objective-C কি C এর উপড়ের লেয়ারের কিছু?” তাহলে আপনার দুটো ধারনাই একদম ঠিক 🙂
আগেও বলা হয়েছে, Objective-C হচ্ছে ট্র্যাডিশনাল C কে অবজেক্ট ওরিয়েন্টেড ফিচার দিয়ে তৈরি হওয়া আরেকটি ল্যাঙ্গুয়েজ। C যা যা করতে পারে, Objective-C ও তাই তাই করতে পারে কিন্তু Objective-C এর কিছু কাজ হয়ত C কে দিয়ে হবে না। অর্থাৎ Objective-C কে C এর সুপারসেট বলতে পারেন। C এর সোর্স আপনি Objective-C এর সোর্স ফাইলের মধ্যেই একই সাথে লিখতে পারেন এবং কম্পাইলার এর কাছে পাঠাতে পারেন।
আর তাই, Objective-C এর উপর দখল আনার জন্য আপনাকে সেই মাদার ল্যাঙ্গুয়েজ C এর ব্যাসিক জানতেই হচ্ছে। এই ব্যপারটাকে মাথায় রেখে এই চ্যাপ্টারে ব্যাসিক C এর ব্যপার গুলো ঝালাই করার চেষ্টা করা হবে এবং অবশ্যই তা আমাদের Objective-C এর সাথে কম্বাইন করেই। অর্থাৎ Objective-C এর ভিতরে আমাদের প্রিয় C

কমেন্টঃ
কিচ্ছু বলার নাই। দেখেই বোঝা যাচ্ছে কিভাবে C কোডের মধ্যে কমেন্ট লেখা যায়।

// This is an inline comment

/* This is a block comment.
   It can span multiple lines. */

ভ্যারিয়েবলঃ
একধরনের কন্টেইনার যা কিছু ভ্যালু ধারন করতে পারে। C তে ভ্যারিয়েবল গুলো Typed অর্থাৎ ভ্যারিয়েবল ডিক্লেয়ার করার সময় জানাতে হবে এটা কি ধরনের ভ্যালু ধারন করবে। ভ্যারিয়েবলকে

<Data Type> <Variable Name>

এই প্যাটার্নে ডিক্লেয়ার করা হয়। যেমন, আমাদের আগের চ্যাপ্টারে করা Command Line Tool টাইপের অ্যাপটির main.m ফাইল নিচের মত করে এডিট করে Command+R চেপে রান করে দেখতে পারি,

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        double bill = 100.50;
        NSLog(@"Total bill: %.2f", bill);
        
    }
    return 0;
}

এখানে bill একটি double টাইপ ভেরিয়েবল যেটা আমরা কনসোলে প্রিন্ট করছি।

কন্সট্যান্টঃ
যে ভেরিয়েবলের ভ্যালু চেঞ্জ করা যায় না। কম্পাইলারকে সেই ভেরিয়েবলের কথা জানাতে const নামক ভেরিয়েবল মডিফায়ার ব্যবহার করা হয়।

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        double const tax = 15.50;
        tax = 10.00;
        NSLog(@"You have to pay a tax of: %.2f %%", tax);
        
    }
    return 0;
}

উপড়ের মত করে ভ্যালু চেঞ্জ করতে গেলে প্রথমেই Xcode বাধা দিবে নিচের মত করে। অন্য ভাবে কম্পাইল করতে গেলেও কম্পাইলার এরর দিবে। তাই, লাইন নাম্বার 9 এখানে অবাঞ্ছিত।
Screen Shot 2014-05-06 at 2.46.18 AM

অ্যারিদম্যাটিকঃ
আমাদের আলোচিত অ্যাপ এর main.m ফাইল নিচের মত করে পরিবর্তিত করে Command+R চেপে রান করে দেখলেই বুঝতে পারবেন কোডের কমেন্ট এ দেয়া বর্ণনা অনুযায়ী C এর ব্যাসিক অ্যারিদম্যাটিক অপারেশন গুলো মনে পরছে কিনা।

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {
        
        NSLog(@"6 + 2 = %d",  6 + 2);   // Addition. Output: 8
        NSLog(@"6 - 2 = %d",  6 - 2);   // Subtraction. Output: 4
        NSLog(@"6 * 2 = %d",  6 * 2);   // Multiplication. Output: 12
        NSLog(@"6 / 2 = %d",  6 / 2);   // Division. Output: 3
        NSLog(@"6 %% 2 = %d", 6 % 2);   // % modulo operator for getting Remainder. Output: 0
        
        int i = 0;
        i++;    // increment operator
        NSLog(@"I was 0 and now I am: %d", i);
        
    }
    return 0;
}

কন্ডিশনালঃ
C তে অন্যান্য ল্যাঙ্গুয়েজের মত if else ফিচার আছে যার ব্যবহার নিচের মত,

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {
        
        double bill = 500;
        if (bill >= 400) {
            NSLog(@"You ate enough");
        } else if (bill <= 100) {
            NSLog(@"You ate least");
        } else {
            NSLog(@"You tool a good meal!");
        }
        
    }
    return 0;
}

এর সাথে সাথেই চলে আসে সবচেয়ে সাধারণ লজিক্যাল অপারেটর গুলোর কথা যেগুলো এই if else এর সাথে সব সময়ই ব্যবহৃত হয়,

        a == b	Equal to
        a != b	Not equal to
        a > b	Greater than
        a >= b	Greater than or equal to
        a < b	Less than
        a <= b	Less than or equal to
        !a	Logical negation
        a && b	Logical and
        a || b	Logical or

আর switch তো আছেই। কিন্তু switch এ শুধু মাত্র integer ভেরিয়েবল ব্যবহার করা যায় এর সুইচিং ফ্যাক্টর হিসেবে।

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {
        
        int bill = 50;
        
        switch (bill) {
            case 500:
                NSLog(@"You ate exactly 500 Tk.");
                break;
            case 400:
                NSLog(@"You ate exactly 100 Tk");
                break;
            case 300:
            case 200:
                NSLog(@"You ate less than 300 Tk.");
                break;
            default:
                NSLog(@"Do not you how much you ate.");
                break;
        }
        
    }
    return 0;
}

উপড়ের if else এবং switch এর ব্যবহার ওয়ালা উদাহরণ দুইটা main.m ফাইলে লিখে শুধুমাত্র Command+R চেপেই রান করে দেখতে পারেন Xcode এর ডিবাগ কনসোলে কি আউটপুট আসে।

লুপঃ
কোন ভ্যালুর মান ও অবস্থার উপর নির্ভর করে একটা কাজ বার বার করা হয় for এবং while লুপ ব্যবহার করে নিচের মত করে,

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {
        
        int totalItem = 5;
        
        for (int itemNumber = 1; itemNumber <= totalItem; itemNumber++) {
            if (itemNumber == 3) {
                NSLog(@"Do not add this item in my dish");
                continue;
            }
            NSLog(@"Added item number: %d", itemNumber);
        }
        
    }
    return 0;
}
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {
        
        int totalItem = 15;
        
        int itemNumber = 1;
        while (itemNumber <= totalItem) {
            if (itemNumber > 5) {
                NSLog(@"Please, Do not add any more food in my dish");
                break;
            }
            NSLog(@"Added item number: %d", itemNumber);
            itemNumber++;
        }
        
    }
    return 0;
}

ম্যাক্রোঃ
সিম্বোলিক কন্সট্যান্ট ডিফাইন করার এক ধরনের লো-লেভেল এর পদ্ধতি। এটা ঠিক কন্সট্যান্ট ভেরিয়েবলের মত নয়। #define ডিরেক্টিভ ম্যাক্রো এর নাম থেকে Expansion ঠিক করে দেয়। মূলত Expansion হচ্ছে কিছু ক্যারেক্টারের সমন্বয়। কম্পাইলার কোড পড়ে ফেলার আগেই প্রিপ্রসেসর সব গুলো ম্যাক্রো এর নামের জায়গায় সেটার Expansion দিয়ে রিপ্লেস করে দেয়। নিচের উদাহরণটা দেখলে পরিষ্কার হবে আশা করছি,

#import <Foundation/Foundation.h>

#define PI 3.14159

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {

        NSLog(@"Whats the value of PI? It is: %f", PI);
        
    }
    return 0;
}

এখানে দেখুন কিভাবে main() ফাংশনের স্কোপের বাইরে থেকেও PI এর একটা মান ব্যবহার করা যাচ্ছে। এখানে PI কে অবজেক্ট টাইপ ম্যাক্রো বলা হয়। C তে ফাংশন টাইপ ম্যাক্রোও আছে যেমন নিচের উদাহরণ,

#import <Foundation/Foundation.h>

#define PI 3.14159
#define circleName @"Pizza"
#define RAD_TO_CIRCUM(radius) (2*PI*radius) // Calculate circumference of a circle

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {

        int radius = 6;
        NSLog(@"Circumference of this %@ is: %f", circleName, RAD_TO_CIRCUM(radius));
        
    }
    return 0;
}

এখানে RAD_TO_CIRCUM() একটি ফাংশন টাইপ ম্যাক্রো যেটা কিনা আবার আর্গুমেন্টও রিসিভ করতে পারে।

স্ট্রাকচারঃ
C এর struct ব্যবহার অনেক গুলো বিভিন্ন রকম ভেরিয়েবলকে একত্রিত করে একটা নতুন ডাটা প্যাকেজ/গ্রুপ হিসেবে ডিফাইন করা যায়। পরে সেই ডাটা গ্রুপটাকে একটা অবজেক্ট এর মত ব্যবহারও করা যায়। নিচে একটা পিৎজার জন্য দরকারি তথ্যের ভেরিয়েবল গুলো গ্রুপ করে একটা নতুন ডাটা স্ট্রাকচার তৈরি করা হয়েছে। আর C এর typedef (নতুন data type ডিক্লেয়ার করার পদ্ধতি) ব্যবহার করে এই নতুন স্ট্রাকচারটিকে Pizza টাইপের data type হিসেবে যাতে ডিল করা যায় সে ব্যবস্থা করা হয়েছে।

#import <Foundation/Foundation.h>

typedef struct {
    unsigned int diameter;
    char mainIngredient[10];
    char pizzaName[10];
} Pizza;

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {

        Pizza makePizza = {6, "beef", "italian"};
        NSLog(@"You are making one : %d inch %s %s pizza!", makePizza.diameter, makePizza.pizzaName, makePizza.mainIngredient);
        
    }
    return 0;
}

এখানে ফাংশনের কাজের শুরুতে makePizza নামের একটি Pizza টাইপ ভেরিয়েবল (এক্ষেত্রে স্টাকচার) এর জন্য ডাটা পপুলেট/এসাইন করা হয়েছে একটি Initializer syntax এর মাধ্যমে।

ইনিউমেরেশন (enum) ঃ
enum কি-ওয়ার্ড ব্যবহার করে একটি enumerated type তৈরি করা হয় যেটাকে আসলে একাধিক কন্সট্যান্ট ভেরিয়েবলের (enumerators) সমষ্টিও বলা যেতে পারে যেখানে কন্সট্যান্ট ভেরিয়েবল গুলোর মান বাই ডিফল্ট সিরিয়ালি 0,1,2,3 … হিসেবে ডিফাইন হয়ে থাকে।

#import <Foundation/Foundation.h>

typedef enum {
    Beef,
    Chicken,
    Mutton
} Pizza;

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {

        Pizza makePizza = Chicken;
        
        NSLog(@"Chicken has position %u in the enumerated type Pizza.", makePizza);
        
        switch (makePizza) {
            case Beef:
                NSLog(@"A beef pizza is coming!");
                break;
            case Chicken:
                NSLog(@"A chicken pizza is coming!");
                break;
            case Mutton:
                NSLog(@"A mutton pizza is coming!");
            default:
                break;
        }
        
    }
    return 0;
}

প্রথমত, আগের মত এই উদাহরণেও typedef ব্যবহার করা হয়েছে। অতঃপর, এখানে যে Enumerated type টি তৈরি করা হয়েছে তার মধ্যে Beef একটি কন্সট্যান্ট ভেরিয়েবল যার মান 0, Chicken এর 1 এবং Mutton এর 2 এভাবে কল্পনা করা যেতে পারে। আর ঠিক এভাবেই, switch এর যে একমাত্র integer টাইপের উপরই নির্ভরতা সেটা দুর করে এর মধ্যে প্রয়োজনে string নিয়েও কাজ করা যেতে পারে। এই প্রোগ্রামটি রান করলে নিচের মত আউটপুট আসবেঃ
Screen Shot 2014-05-07 at 2.45.49 AM

অ্যারেঃ
যদিও iOS/OSX অ্যাপ ডেভেলপমেন্টের সময় Foundation ফ্রেমওয়ার্কের সাথে থাকা হাই লেভেল NSArray এবং NSMutableArray ক্লাস গুলো দিয়ে অ্যারে অপারেশন করাই হবে সবচেয়ে সুবিধা জনক তবুও এখানে যেহেতু C নিয়েই একটু স্মৃতিচারণ করা হচ্ছে এবং C এর অ্যারেকেও Objective-C এর সাথে ব্যবহার করা যাবে তাই নিচে থাকছে অ্যারে এর উদাহরণ,

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {

        int pizzaSize[3] = {6, 12, 18};

        for (int i=0; i<3; i++) {
            NSLog(@"Pizza at index %d is: %d inch", i, pizzaSize[i]);
        }
        
    }
    return 0;
}

অ্যারে ডিক্লেয়ার করার int pizzaSize[3] স্টেটমেন্টটি শুরুতেই ৩টা অনুক্রমিক মেমোরি ব্লক অ্যালোকেট করে নেয় যেখানে integer টাইপের ডাটা অনায়াসে ধরবে। তারপরেই initializer syntax ব্যবহার করে সেই অ্যারেটিকে পপুলেট করা হচ্ছে অর্থাৎ ডাটা এসাইন করা হচ্ছে। এরপর pizzaSize[] এর মধ্যে i এর মান অর্থাৎ 0,1 বা 2 অফসেট হিসেবে দিয়ে ওই অ্যারের ভ্যালু গুলো এক্সেস করা হচ্ছে। যেহেতু অ্যারেতে যেহেতু অনুক্রমিক ভাবেই ডাটা থাকে তাই অফসেট এর সাথে ১ যোগ করে দিয়ে দিয়েই পরের অফসেটের ভ্যালু পাওয়া যাচ্ছে।

পয়েন্টারঃ
পয়েন্টার হচ্ছে মেমোরি অ্যাড্রেস এর রেফারেন্স। একদিকে যেমন, ভেরিয়েবল হচ্ছে ভ্যালু রাখার কন্টেইনার অন্যদিকে পয়েন্টার হচ্ছে মেমোরিতে ভ্যালুটি যেখানে জমা আছে সেখানকার অ্যাড্রেস এর রেফারেন্সে হোল্ডার। & হচ্ছে রেফারেন্স অপারেটর যা একটি সাধারণ ভেরিয়েবলের মেমোরি অ্যাড্রেস রিটার্ন করে। সেটাই পয়েন্টার এর মধ্যে জমা রাখা হয়।
আর যখন সেই মেমোরি অ্যাড্রেস এ থাকা ভ্যালুটির দরকার হয় তখন * ডি-রেফারেন্স অপারেটর ব্যবহার করে পয়েন্টারে জমা থাকা মেমোরি অ্যাড্রেস এর কন্টেন্ট বা ভ্যালুকে এক্সেস করা যায়। আবার এই ডি-রেফারেন্স অপারেটর ব্যবহার করেই ওই মেমোরি অ্যাড্রেসে নতুন ভ্যালু সেটও করা যায়। নিচের উদাহরণ দেখলে আরেকটু ক্লিয়ার হবে,

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {
        // Define a normal variable
        int bill = 500;
        // Declare a pointer that points to an int
        int *pointer;
        
        // Find the memory address of the variable
        pointer = &bill;
        // Dereference the address to get its value
        NSLog(@"Your bill is: %d Tk", *pointer);
        
        // Assign a new value to the memory address
        *pointer = 525;
        // Access the chnaged value via the variable
        NSLog(@"Your bill including tax is: %d Tk", bill);

        
    }
    return 0;
}

Void Pointer নামের একধরনের পয়েন্টার আছে যা আসলে যেকোনো কিছুকেই পয়েন্ট করতে পারে। অর্থাৎ নির্দিষ্ট করে প্রথম থেকেই যে একটা integer বা char কে পয়েন্ট করবে/করছে, তা নয়। কিন্তু ওই ভয়েড পয়েন্টারে জমা থাকা মেমোরি অ্যাড্রেস ধরে সেখানকার ভ্যালু বা কন্টেন্ট এক্সেস করতে হলে একটু কাজ করতে হবে অর্থাৎ পয়েন্টার কে বলতে হবে ওই অ্যাড্রেস থেকে কোন ফরম্যাট হিসেবে ডাটা পড়বে। নিচে একটি উদাহরণ আছে,

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {

        int toPay = 500;
        
        void *genericPointer = &toPay;
        int *intPointer = (int *)genericPointer; // Casting to non-void pointer
        
        NSLog(@"To pay actually: %d", *intPointer);
        
    }
    return 0;
}

এখানে ভয়েড পয়েন্টারটিকে cast করে নন-ভয়েড এবং integer টাইপের পয়েন্টারে রূপান্তর করা হচ্ছে। (int *) স্টেটমেন্টটি ভয়েড পয়েন্টারের কন্টেন্ট কে integer হিসেবে interpret করছে।

Objective-C তে পয়েন্টারঃ
Objective-C তে পয়েন্টারের ব্যপারটা খুব কম কথাতেই শেষ হয়ে যাবে কিন্তু ভালো মতই মনে রাখতে হবে যে সব রকম Objective-C এর অবজেক্টকে পয়েন্টার হিসেবে উল্লেখ করা হয়। যেমন নিচের মত করে, একটা NSString অবজেক্টকে অবশ্যই পয়েন্টার হিসেবে স্টোর করতে হবে, নরমাল ভেরিয়েবল হিসেবে নয়।

NSString *foodItem = @"Beef Pizza";

ভেরিয়েবল ডিক্লেয়ারেশন বাদে বাকি সব সময়ের জন্য Objective-C এর সিনট্যাক্সকে পয়েন্টার হিসেবে কাজ করার উপযোগী করেই তৈরি করা হয়েছে। তাই, একবার একটি অবজেক্ট পয়েন্টার ডিফাইন করার পর থেকেই সেটাকে একটা নরমাল ভেরিয়েবল মনে করে সেটার সাথে ডিল করা যেতে পারে। এতে করে ব্যপারটা সহজবোধ্য হবে।

পরের চ্যাপ্টারঃ
ব্যাসিক C এর ফাংশন নিয়ে একটু আলোচনা করেই Objective-C তে ফাংশনের ডিক্লেয়ারেশন, ডেফিনেশন নিয়ে আলোচনা হবে। তার পর পরই, এই যে Objective-C আমাদের প্রিয় C এর সাথে object oriented feature জুড়ে দিয়ে C দিয়েও OOP বেজড প্রোগ্রামিং করার রাস্তা তৈরি করলো, সেটার ব্যবহার অর্থাৎ Objective-C এর ক্লাস, প্রোপার্টি, মেথড নিয়ে আলোচনা হবে।

পরের চ্যাপ্টার – ৩ঃ OBJECTIVE-C তে ফাংশন ও এর ব্যবহার

২-১ঃ Xcode 5 এ অবজেক্টিভ-সি দিয়ে iOS7 এর জন্য প্রথম হ্যালো ওয়ার্ল্ড এপ্লিকেশন যেভাবে করব

Standard

এই সিরিজের পুরো পোস্ট লিস্ট এবং সম্ভাব্য কাগুজে বই এর সূচি দেখতে ক্লিক করুনbangla-ios-objective-c-swift-nuhil

ভূমিকাঃ
স্বাগত জানাচ্ছি আপনার iOS এপ্লিকেশন নিয়ে আগ্রহের জন্য। এটি আমাদের উপরে উল্লেখিত সিরিজের দ্বিতীয় সেকশনের প্রথম চ্যাপ্টার। প্রথম সেকশনের ১০টি চ্যাপ্টারের মাধ্যমে সহজ বাংলায় অবজেক্টিভ-সি এর ব্যাসিক লার্নিং কোর্স সম্পন্ন হয়েছে। আপনি যদি ওই সেকশনের কোর্স গুলো ফলো করে না থাকেন তাহলে উপরের সূচি ঘুরে আসতে পারেন।
আজকে আমরা শেয়ার করব কিভাবে আপনি  Xcode 5 এ অবেজক্টিভ-সি দিয়ে iOS7 এর জন্য সহজ একটি হ্যালো ওয়ার্ল্ড এপ্লিকেশন তৈরি করতে পারেন।

কি কি জিনিস অবশ্যই লাগবেঃ 
১. Mac OS X চালিত ম্যাক কম্পিউটার সিস্টেম – এটাই প্রথম ও প্রধান দরকারী জিনিস। আপনি একটি ম্যাক বুক, ম্যাক বুক প্রো, আই ম্যাক অথবা ম্যাক মিনি ব্যবহার করতে পারেন এবং সেটাতে সর্বশেষ হালনাগাদ করা (OS X 10.8.5 Mountain Lion) অপারেটিং সিস্টেম ব্যবহার করতে পারেন।
২. একটি ফ্রি Apple ডেভেলপার একাউন্ট – নতুন একাউন্ট খুলতে পারেন এখান থেকে
৩. Xcode 5 – আমি আগেই বলেছি এখানে আলোচিত সব গুলো পোস্ট লেখা হবে Xcode 5 এ কোড করে ও এর অন্যান্য সুবিধা গুলো ব্যবহার করে। আপনার যদি ম্যাক থাকে এবং সেটার অপারেটিং সিস্টেম 10.8.4 এর পরের যেকোনো ভার্সন হয় তাহলে আপনি সেটাতে Xcode 5 ইনস্টল/আপডেট করতে পারবেন। Xcode প্রথমত একটি ইন্টিগ্রেটেড ডেভেলপমেন্ট এনভায়রনমেন্ট বা আই, ডি, ই। এটার সাথে iOS এবং OSX এর জন্য সফ্টওয়্যার ডেভেলপমেন্ট কিট বা এস, ডি, কে টিও থাকে। উপরন্তু এটি একটি একটি সোর্স কোড এডিটর যার সাথে ডিবাগিং টুল এবং সুন্দর একটি ইউজার ইন্টারফেস (ইউ, আই ) বিল্ডার এবং একটি এপ্লিকেশন সিমুলেটরও আছে।
আপাতত আর কিছু না।

শুরু করি হ্যালো ওয়ার্ল্ডঃ
Continue reading