ম্যাক এর জন্য ডেভেলপার বা প্রো-ইউজারদের প্রয়োজনীয় ৩০টি অ্যাপ সাজেশন

Standard
  1. Xcode যারা iOS, watchOS বা macOS এর জন্য অ্যাপ্লিকেশন ডেভেলপ করতে চান তাদের জন্য একান্ত প্রয়োজনীয় একটি IDE যার সাথে বিল্ট ইন আছে ইমুলেটর গুলোও। ম্যাক ইউজাররা ফ্রি তেই ডাউনলোড করতে পারবেন।
  2. chrome বর্তমান ওয়েব দুনিয়ায়, সব ব্রাউজারের ব্যবহার জরিপ অনুযায়ী শতকরা ৭০ ভাগেরও বেশি ব্যবহৃত হয় গুগলের তৈরি এই ব্রাউজারটি। বিশাল এক্সটেনশন এবং অ্যাপ মার্কেটপ্লেস এই ব্রাউজারকে করেছে আরও সমৃদ্ধ। এই ব্রাউজারে যেমন ক্লায়েন্ট সাইড ডিবাগিং, ইন্সপেকশন টুল বিল্ট আছে তেমনি এর জন্য এক্সটেনশন বা প্লাগিন তৈরি করাও বেশ সহজ। সবার জন্য ফ্রি।
  3. PhpStorm জেট ব্রেইন্স এর তৈরি সবচেয়ে পপুলার একটি IDE যার মাধ্যমে PHP -তে ওয়েব অ্যাপ ডেভেলপমেন্ট হতে পারে খুবি প্রোডাক্টিভ। স্টুডেন্টদের জন্য ফ্রি। এছাড়াও স্টার্ট আপ, ট্রেনিং সেন্টার বা ওপেন সোর্স প্রোডাক্ট ডেভেলপারদের জন্যও ফ্রি/ছাড়।
  4. PyCharm জেট ব্রেইন্স এর তৈরি আরেকটি বহুল পরিচিত পাইথন IDE যার একটি কমিউনিটি এডিশন আছে যেটি সবসময় বিনামূল্যে পাওয়া যায়। পাইথন অ্যাপ ডেভেলপার বা পাইথন স্ট্যাকে কাজ করেন এমন ইউজারদের জন্য খুবি প্রোডাক্টিভ একটি টুল। যারা Anaconda এর মত রেডি মেড প্ল্যাটফর্ম এর জন্য বাধ্য না, সেরকম ডাটা সায়েন্স ইঞ্জিনিয়াররাও এটায় কাজ করতে পারেন স্বাচ্ছন্দ্যে. এর প্রফেশনাল এডিশনটি স্টুডেন্টদের জন্য ফ্রি। এছাড়াও স্টার্ট আপ, ট্রেনিং সেন্টার বা ওপেন সোর্স প্রোডাক্ট ডেভেলপারদের জন্যও ফ্রি/ছাড়।
  5. Webstorm যাদের জাভাস্ক্রিপ্ট স্ট্যাক খুব পছন্দ এবং ক্লায়েন্ট সাইড অ্যাপ ডেভেলপমেন্টে ফোকাসড তাঁরা ব্যবহার করতে পারেন এই IDE টি. এমনকি MEAN স্ট্যাকে ডেভেলপমেন্ট করতে চাইলেও এই IDE হতে পারে প্রথম পছন্দ। স্টুডেন্টদের জন্য ফ্রি।
  6. IntelliJ IDEA জাভা ডেভেলপারদের জন্য অত্যন্ত চমৎকার ফিচার সমৃদ্ধ একটি IDE. স্কালা, গ্রুভি, কটলিন ল্যাঙ্গুয়েজের সাপোর্ট থেকে শুরু করে গিট সাপোর্ট এবং স্প্রিং এর মত ফ্রেমওয়ার্ক সাপোর্ট সবই আছে এতে। Android অ্যাপ ডেভেলপমেন্ট থেকে শুরু করে ওয়েব অ্যাপ ডেভেলপমেন্ট, সবই সম্ভব এই প্রোডাক্টিভ টুলটি ব্যবহারের মাধ্যমে। স্টুডেন্টদের জন্য ফ্রি।
  7. Android Studio অ্যান্ড্রয়েড অ্যাপ ডেভেলপমেন্ট এর জন্য একমাত্র অফিসিয়াল IDE. কোড এডিটিং, ডিবাগিং থেকে শুরু করে পারফরমেন্স টেস্টিং, ডিপ্লয়েমেন্ট, ইনস্ট্যান্ট বিল্ড ও অনেক অনেক ফিচার সমৃদ্ধ IDE টি অ্যান্ড্রয়েড অ্যাপ ডেভেলপারদের প্রথম পছন্দ। ফ্রি।
  8. Visual Studio Code মাইক্রোসফট এর তৈরি ফ্রি, ওপেন সোর্স এবং সুন্দর ইন্টারফেইস সমৃদ্ধ এই মাল্টি প্ল্যাটফর্ম কোড এডিটরটি লাইট ওয়েট এবং সাথে গিট ও ডিবাগিং ফিচার বিল্ট ইন। আরও আছে কমিউনিটির ডেভেলপ করা মারাত্মক সব এক্সটেনশন। ফ্রি.
  9. Docker এটি বর্তমানের সব চেয়ে পপুলার সফটওয়্যার কন্টেইনার প্ল্যাটফর্ম। মাল্টি প্ল্যাটফর্মে ডেভেলপমেন্ট, ফুল ডেভেলপমেন্ট এনভায়রনমেন্ট পোর্ট, অতঃপর দ্রুত ডেপ্লয়মেন্ট এবং সহজ স্কেল্যাব্লিটির জন্য সবাই এখন ব্যবহার করছে এই টুলটিকে। কমিউনিটি এডিশন ফ্রি।
  10. VirtualBox ম্যাকের মধ্যেই Windows বা Ubuntu বা অন্য কোন OS ইন্সটল দিতে চাইলে ভার্চুয়াল বক্স হতে পারে সলিড একটি সমাধান। এছাড়া ম্যাকে Vagrant ব্যবহার করতে হলেও এটি আগে ইন্সটল থাকতে হবে। ফ্রি তেই পাওয়া যাবে এই সফটওয়্যারটি।
  11. Vagrant ভার্চুয়াল বক্স ইউজ করে অন্য OS ইন্সটল দেয়ার পরেও কিছু সীমাবদ্ধতা থেকে যায় যেগুলো দূর করতে পারে এই কমান্ড লাইন অ্যাপটি। এটি ব্যবহার করে খুব দ্রুত যেকোনো হেড লেস OS ইন্সটল দেয়া এবং সাথে সাথে IP, Memory, Sync Folder, SSH ইত্যাদি কনফিগার করা যায় সহজেই। ফ্রি.
  12. Sequel Pro গ্র্যাফিক্যালি MySQL ডাটাবেজ ম্যানেজমেন্টের জন্য ম্যাকের উপযোগী খুব সুন্দর একটি অ্যাপ। ম্যাকের জন্য ফ্রিতেই পাওয়া যায়।
  13. Robomongo ক্রস প্ল্যাটফর্ম এবং ন্যাটিভ একটি গ্রাফিক্যাল টুল যা দিয়ে সহজেই MongoDB ম্যানেজ করতে পারেন।
  14. iTerm2 ম্যাকের বিল্ট ইন টার্মিনাল অ্যাপ এর চেয়ে অনেক বেশি কনফিগারেবল এবং অনেক অনেক ফিচার সমৃদ্ধ একটি টার্মিনাল ক্লায়েন্ট। ওপেন সোর্স এবং সম্পূর্ণ ফ্রি।
  15. Postman বর্তমানে সফটওয়্যার ডেভেলপমেন্ট এবং API ডেভেলপেমণ্ট প্রায় ওতপ্রোতভাবে জড়িত। আর পোষ্টম্যান হচ্ছে সেখানে অবশ্য প্রয়োজনীয় একটি অ্যাপ যার মাধ্যমে আপনার ডেভেলপ করা API এন্ডপয়েন্ট গুলোকে টেস্ট করতে পারবেন সহজেই।
  16. Homebrew এক কথায় একে বলা হয় The missing package manager for macOS. অর্থাৎ, যারা উবুন্টু বা এরকম ইউনিক্স সিস্টেমের বিল্ট ইন প্যাকেজ ম্যানেজার গুলোকে পছন্দ করেন এবং ম্যাকে এরকম একটি টুলকে মিস করেন তাদের জন্য লাইফ সেভার একটি টুল এটি। মজার বিষয় হচ্ছে, এটি কোন টুল ইন্সটল করার সময় এর নিজের একটি আলাদা লোকেশন ইন্সটল করে এবং সেটির একটি সিম্বোলিক লিঙ্ক ম্যাকের /usr/local ডিরেক্টরিতে তৈরি করে. আর তাই আপনার সিস্টেম ক্লিন থাকে।
  17. Github Desktop যদি আপনি একজন ওপেন সোর্স কন্ট্রিবিউটর হয়ে থাকেন এবং বিভিন্ন github রিপজিটরিতে খুব দ্রুত একটি গ্রাফিক্যাল টুল ইউজ করে কোলাবরেট করতে চান তাহলে এটি আপনার জন্য। এটি ফ্রি। Tower হচ্ছে এরকমই আরেকটি অ্যাপ যা আপনার সব গিট রিপজিটরির জন্য কিন্তু এটি পেইড অ্যাপ।
  18. FileZilla নানা কারণেই আপনার একটি FTP ক্লায়েন্ট দরকার হতে পারে যে ক্ষেত্রে এই ফ্রি, ওপেন সোর্স এবং ক্রস প্ল্যাটফর্ম অ্যাপটি হতে পারে প্রথম পছন্দের। FTP, SFPT সাপোর্ট রয়েছে এতে।
  19. Caffeine ছোট একটি টুলবার অ্যাপ যার মাধ্যমে নির্দিষ্ট সময়ের জন্য আপনার ম্যাককে স্লিপ মুডে যাওয়া থেকে বিরত রাখতে পারেন. ফ্রি।
  20. Spectacle ম্যাক ইউজারদের কাছে অনেক সময় বিরক্তির কারণ হয়ে দাড়ায় বিভিন্ন অ্যাপ উইন্ডোর সাইজকে ঠিক ঠাক করা। এই টুলবার অ্যাপ এবং এর কিবোর্ড শর্ট কাট এর মাধ্যমে খুব সহজেই কোন রানিং অ্যাপকে ফুল সাইজ করা, অর্ধেক ডানে বা অর্ধেক বামে করা ইত্যাদি নানা রকম প্লেসমেন্ট করা যায়। ফ্রি।
  21. Skype নতুন করে বলার কিছু নাই স্কাইপি নিয়ে। মার্কেটে অনেক সময় অনেক রকম কমিউনিকেশন টুল আসলেও এর অবস্থান অনড়। এখনও অনেক ইউজাররা মিটিং, স্ক্রিন শেয়ারিং, গ্রুপ কনভারসেশন এমনকি কলিং এর জন্য এর উপরেই ভরশা করে থাকেন. ফ্রি.
  22. Slack এটি আধুনিক একটি যোগাযোগের মাধ্যম যা চ্যাটিং ইন্টাফেইসকে ঘিরেই তৈরি। এটি বিশেষ করে ব্যবহৃত হয় অফিস বা টিমের মধ্যে। বিভিন্ন গ্রুপ বা চ্যানেল তৈরির মাধ্যমে মেম্বাররা নিজেদের মধ্যে চ্যাট, মেনশন, ফাইল শেয়ারিং ইত্যাদি করতে পারেন। এর জন্য বিভিন্ন বট তৈরি করেও একে আরও বেশি প্রয়োজনীয় এবং উপযোগী করে নিতে পারেন যে কেউ। ফ্রি.
  23. Dropbox ক্লাউড স্টোরেজের জন্য অত্যন্ত নির্ভরযোগ্য একটি প্ল্যাটফর্ম। এর ম্যাক অ্যাপটি টুলবারে থেকে খুব সহজেই আপনার প্রয়োজনীয় ফাইলকে ক্লাউডে সিঙ্ক করে নেয়। ম্যাক যেকোনো ফাইল তৈরি করার পর শুধু সেভ করার লোকেশনটি দেখিয়ে দিবেন Dropbox এর সিঙ্ক করা যেকোনো একটি ফোল্ডারে। সাথে সাথে এটি ক্লাউডে আপলোড হয়ে যাবে। অন্য ইউজারদের সাথে ফাইল শেয়ার করতেও ব্যবহার করা যায় এদের সার্ভিসকে। নির্দিষ্ট জায়গা পর্যন্ত ফ্রি।
  24. Office 365 যে যাই বলুক, মাইক্রোসফট এর তৈরি এই অফিস স্যুটটির ভাল কোন বিকল্প এখনও নেই। এর মধ্যে থাকে MS Word, MS Excel, MS Power Point এবং আরও কয়েকটি অত্যন্ত দরকারি অ্যাপ যা একাধারে ছাত্র, শিক্ষক, লেখক, হিসাবরক্ষক, চাকুরীজীবী সবার কাছেই গুরুত্বপূর্ণ। ছাত্রদের জন্য ফ্রি।
  25. Sketch অ্যাপ, ওয়েব পেইজ বা লে-আউট ডিজাইনাদের জন্য Photoshop এর বিকল্প এবং ম্যাকের জন্য বহুল ব্যবহৃত একটি অ্যাপ। যাদের Photoshop এর সব ফিচার দরকার নাই বা শুধুমাত্র অ্যাপ ডিজাইন নিয়েই ফোকাস করতে চান তাদের জন্য। এটি একটি পেইড অ্যাপ।
  26. VLC Media Player সবার অত্যন্ত পরিচিত একটি মিডিয়া প্লেয়ার। এটি ফ্রি এবং ওপেন সোর্স।
  27. uTorrent ম্যাকের জন্য একটি টরেন্ট ক্লায়েন্ট দরকার হলে এটি হতে পারে পছন্দের। যদিও অনেকে এই পারপাজে Transmission ব্যবহার করে থাকেন।
  28. Dash লিস্টের শেষের দিকে লিখছি মানেই যে এটি কম গুরুত্বপূর্ণ একটি অ্যাপ, বিষয়টি তা নয়। বরং, এটি লিস্টের শুরুতেও থাকতে পারতো। আপনার মাথায় যতরকম প্রোগ্রামিং ল্যাঙ্গুয়েজ, ফ্রেমওয়ার্ক বা ডেভেলপমেন্ট টুল এর নাম থাকতে পারে- প্রায় সবগুলোর ডকুমেন্টেশন অফলাইনেই ব্রাউজ করতে চাইলে এই অ্যাপের কোন বিকল্প নাই। এছাড়াও এতে আছে সুন্দর একটি snippet ম্যানেজার। ব্যাসিক ভার্সন ফ্রি.
  29. Dr. Cleaner ম্যাকের জন্য প্রয়োজনীয় একটি ইউটিলিটি অ্যাপ। এর মাধ্যমে একাধারে ডিস্ক ক্লিন আপ, মেমরি ক্লিনআপ এবং সিস্টেম অপটিমাইজেশনের মত কাজ গুলো সহজেই করা যায়। এর মাধ্যমে- সাইজ মোতাবেক পুরো ম্যাকের সব ফাইলকে লিস্ট করা যায় যাতে করে কোন ফাইল বা অ্যাপ কেমন জায়গা নিচ্ছে তার একটা আইডিয়া পাওয়া যায় এবং প্রয়োজনে সেটা ডিলিট বা রিমুভ করা যায়.
  30. AppCleaner ম্যাক থেকে যেকোনো রকম অ্যাপ, উইজেট বা প্লাগিন পুরোপুরি আনইন্সটল করতে চাইলে এই ছোট্ট অ্যাপটি আপনাকে সলিড কাজ করে দেখাবে।
বিঃ দ্রঃ এই লিস্টের বাইরেও আরও অনেক প্রয়োজনীয় এবং গুরুত্বপূর্ণ অ্যাপ/টুল আছে যেগুলো নির্দিষ্ট কাজের জন্য নির্দিষ্ট ইউজারের কাছে দরকারি।

macOS -এ আপনি কি কি অ্যাপ ব্যবহার করে থাকেন এবং কোন সাজেশন থাকলে কমেন্ট করুন নিচে

এঞ্জিনএক্স, পিএইচপি, মাইএসকিউএল এর ইনস্টলেশন, কনফিগারেশন এবং সার্ভার ব্লক (ভার্চুয়াল হোস্ট) তৈরি

Standard

সবার জন্য প্রোগ্রামিং

সার্ভারের প্রাথমিক এবং ব্যাসিক কনফিগারেশন

1. নতুন তৈরি হওয়া সার্ভারে root ইউজার হিসেবে লগইন করুন নিচের কমান্ড দিয়ে

2. নতুন একটি ইউজার তৈরি করতে কমান্ড দিন নিচের মত। এখানে নতুন ইউজারের নাম demo

3. নতুন ইউজারকে root ইউজারের সমতুল্য অধিকার দিতে তাকে sudo গ্রুপে যুক্ত করুন

4. পাসওয়ার্ডের পরিবর্তে পাবলিক কি দিয়ে অথেনটিকেশন এর ব্যবস্থা

  • আপনার লোকাল মেশিনে এক জোড়া কি তৈরি করতে কমান্ড দিন (~/.ssh ডিরেক্টরির মধ্যে তৈরি করা ভালো)
  • পাবলিক কি এর কন্টেন্টকে রিমোট সার্ভারে কপি করতে প্রথম এর কন্টেন্ট প্রিন্ট করতে কমান্ড দিন

    এরপর স্বাভাবিকভাবে পুরো আউটপুট সিলেক্ট করে কপি করুন

  • সার্ভারে root ইউজার হিসেবে লগডইন থাকা অবস্থায় নিচের কমান্ড দিয়ে নতুন ইউজার হিসেবে লগইন করুন

    এ অবস্থায় আপনি demo ইউজারের home ডিরেক্টরিতে থাকবেন

  • demo ইউজারের home ডিরেক্টরিতে .ssh নামের একটি ডিরেক্টরি তৈরি করতে এবং সেটার যথাযথ পারমিশন সেট করতে নিচের দুটো কমান্ড পর পর দিন:

  • ওই ডিরেক্টরির মধ্যে authorized_keys নামের ফাইল তৈরি/এডিট করুন

    এবার লোকাল মেশিনের…

View original post 591 more words

রাস্পবেরি পাই পরিচিতি ও প্রথম বুট – ভিডিও

Standard

সবার জন্য প্রোগ্রামিং

Photo Sep 28, 11 54 16 AM
রাস্পবেরি পাই বি+ মডেলের পরিচিত, হার্ডওয়্যার রিভিউ, এর জন্য অপারেটিং সিস্টেম রেডি করা, প্রথম বুট এবং রাস্পবিয়ান এর ব্যাসিক পরিচিত

View original post

parse.com এপিআই ব্যাবহার করে একটি সাধারণ জাভাস্ক্রিপ্ট ওয়েব অ্যাপ তৈরি

Standard

সবার জন্য প্রোগ্রামিং

ভূমিকা

মোবাইল বা অন্যান্য ফ্রন্টএন্ড প্ল্যাটফর্মের জন্য অ্যাপ ডেভেলপমেন্টের সময় প্রায় অর্ধেকেরও বেশি সময় দিতে হয় ব্যাকএন্ডে অর্থাৎ ওই অ্যাপ এর জন্য ডাটাবেজ তৈরি, সার্ভার সাইড লজিক ডিপেন্ডেণ্ট অ্যাপ তৈরি, ফ্রন্টএন্ডের জন্য এপিআই প্রোভাইডার তৈরি এবং সর্বোপরি সেই সার্ভারটা ম্যানেজমেন্ট এর জন্য টিম তৈরি। এসব কিছু অন্য একটা নির্ভরযোগ্য মাধ্যমের কাছ থেকে পেয়ে গেলে আপনার মনোযোগ তখন শুধু থাকবে ফ্রন্টএন্ড অ্যাপ তৈরিতে। এরকম একটি [ব্যাকএন্ড অ্যাজ অ্যা সার্ভিস] হচ্ছে parse.com

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

সবচেয়ে মজার ব্যাপার হচ্ছে এটা একটা ফ্রি সার্ভিস (৩০ এপিআই কল পার সেকেন্ড), ফেসবুকের তত্ত্বাবধানে থাকা একটি কোম্পানি এবং মোটামুটি সব রকম সফটওয়্যার ডেভেলপমেন্ট প্ল্যাটফর্মের জন্য parse এর লাইব্রেরী/এসডিকে আছে…

View original post 1,232 more words

ভিপিএস (VPS) কেনা, ব্যাসিক কনফিগারেশন, ল্যাম্প ইন্সটলেশন, ডোমেইন ম্যাপিং

Standard

সবার জন্য প্রোগ্রামিং

ভূমিকা

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

কিনে ফেলি একটা ভার্চুয়াল প্রাইভেট সার্ভার

বিভিন্ন সার্ভার প্রোভাইডার তাদের মেশিনগুলোকে বিভিন্ন নামে ডাকে। যেমন অ্যামাজন এর ভাষায় এগুলো হচ্ছে ইন্সট্যান্স, Rackspace এর ভাষায় এগুলো ক্লাউড সার্ভার, DigitalOcean এর ভাষায় ড্রপলেট, ইত্যাদি। আমরা আজকের টিউটোরিয়ালের জন্য DigitalOcean এর কাছ থেকে একটি মিনিমাম কনফিগারেশনের সার্ভার কিনবো যেটাতে ৬৪ বিটের…

View original post 2,065 more words

১০- অবজেকটিভ সি তে এক্সেপশন ও এরর হ্যান্ডেলিং

Standard

ভুমিকাঃ
অ্যাপ্লিকেশন ডেভেলপমেন্ট এর সময় যে দুটি প্রধান সমস্যার কথা ডেভেলপার/প্রোগ্রামারদের ভাবতে হয় সেগুলো হল এক্সেপশন ও এরর। iOS ও OS X এ অ্যাপ্লিকেশন চলার সময়ও এক্সেপশন ও এরর ঘটতে পারে।

প্রোগ্রামার লেভেলের বাগ গুলো কে এক্সেপশন বলা হয়। উদাহরনস্বরুপ: যখন কোডের মাধ্যমে কোন অ্যারে (Array) এর ননএক্সিস্টিং ইলিমেন্টকে এক্সেস করার চেষ্টা করা হয় তখন সিস্টেম এক্সেপশন থ্রো করে। অ্যাপ্লিকেশন চলার সময় যদি কোন কারনে এরকম একটা বিষয় উদ্ভূত হয় তাহলে ডেভেলপারকে সেটা সম্পর্কে তথ্য দেয়ার জন্যই প্রোগ্রামিং ল্যাঙ্গুয়েজগুলোতে এক্সেপশন ফিচার ডিজাইন করা হয়েছে। প্রোগ্রামের মধ্যেই প্রোগ্রামারকে এরকম এক্সেপশনাল কেস হ্যান্ডেল করার জন্য প্রয়োজনীয় কোড লিখতে হয় যাকে বলে এক্সেপশন হ্যান্ডেলিং।
Screen Shot 2014-06-10 at 3

এক্সেপশন ডেভেলপার কে জানাও।

অন্যদিকে ইউজার লেভেলে যদি কোন অনাকাঙ্খিত ঘটনা ঘটে সেগুলোকে এরর বলা হয়। যেমন, যদি আপনার অ্যাপ্লিকেশনটির কাজ হয় যে, ডিভাইসের GPS সার্ভিস ব্যবহার করে আসেপাশের কিছু লোকেশন দেখাবে। কিন্তু ইউজার তার ডিভাইসের GPS সেটিং ডিজ্যাবল করে রেখেছে । তখন অ্যাপটা চলার সময় ইউজারকে একটা ম্যাসেজ দেখানো উচিত যে, তার GPS অফ আছে। এরকম অবস্থায় ইউজারকে কিছুই না জানিয়ে অ্যাপ্লিকেশন এর ক্র্যাশ হওয়া উচিত হবে না। তাই এধরনের কন্ডিশনগুলো যখন ঘটবে তখন ম্যানুয়ালী চেক করে সঠিক তথ্যটা বা এরর ম্যাসেজটা ইউজারকে দেওয়াই হচ্ছে এরর হ্যান্ডেলিং।
Screen Shot 2014-06-10 at 3.09.58 PM

ওয়ার্ক এরর ইউজারকে জানাও এবং সম্ভব হলে অ্যাপ রান করতেই থাকো।

কিন্তু মনে রাখবেন, কোডিং এরর আর উপরে উল্লেখিত এররটা কিন্তু এক জিনিস না। যেমন, আপনি আপনার প্রোগ্রামের মধ্যে একটা ক্লাস ইন্সট্যান্সিয়েট করে সেটার কিছু মেথড এক্সেস করতে চাচ্ছেন কিন্তু শুরুতে ওই ক্লাসের হেডার ফাইলকে ইনক্লুড করেন নাই। তখন কিন্তু কম্পাইলার আপনাকে এরর দেবে এবং প্রোগ্রাম রান-ই করবে না। কম্পাইলারকে ডিজাইন করা হয়েছে এরকম কোডিং এরর সম্পর্কে ডেভেলপারকে জানাতে।
Screen Shot 2014-06-10 at 3.17.02 PM

কোডিং এরর ডেভেলপারকে জানিয়ে থেমে যাও

এক্সেপশন (Exceptions)ঃ
অবজেকটিভ-সি তে NSException ক্লাস দিয়ে এক্সেপশনকে রিপ্রেজেন্ট করা হয়। যখন কোন এক্সেপশন ঘটে তখন এই এক্সেপশনের যাবতীয় তথ্য NSException ক্লাসের ইনস্ট্যান্স থেকেই পাওয়া যায়। NSException ক্লাসের ৩টি প্রধান প্রোপার্টি নিচে দেওয়া হলঃ

  • name ঃ এক্সেপশনের নাম (ডাটাটাইপ: NSString ) যা সকল এক্সেপশনের জন্য আলাদা
  • reason ঃ এক্সেপশনের সহজবোধ্য বর্ননা ( ডাটাটাইপ : NSString)
  • userInfo ঃ NSDictionary টাইপের অবজেক্ট। এই অবজেক্টে কি-ভ্যালু রিলেশনশিপ দিয়ে এক্সেপশনের অতিরিক্ত তথ্য থাকে

এক্সেপশন হ্যান্ডেলিং (Exception Handling) ঃ
নিচের মত করে একটি নতুন ফ্রেশ প্রজেক্টের main.m ফাইলটি এডিট করে ফেলিঃ

// main.m

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
    
        // menuList of the restaurant
        NSArray *menuList = @[@"Vegetable Rice", @"Chicken Toast", @"Thai Soup"];
        
        NSLog(@"1st Item Name is %@",  menuList[0]); // Vegetable Rice
        NSLog(@"2nd Item Name is %@",  menuList[1]);  // Chicken Toast
        NSLog(@"3rd Item Name is %@",  menuList[2]);; // Thai Soup
        NSLog(@"3rd Item Name is %@",  menuList[3]);  // throughs exception
    }
    return 0;
}

উপরের প্রোগ্রামটিতে প্রথমেই NSArray টাইপ একটি অ্যারে লিস্ট নেওয়া হয়েছে যাতে ৩ টি আইটেম আছে। আমরা জানি যে অবজেকটিভ সি এবং প্রায় সকল প্রোগ্রামিং লাঙ্গুয়েজেই ০ থেকে ইনডেক্সিং শুরু হয়। সুতরাং menuList অ্যারেতে ০ থেকে ২ এই তিনটি ইনডেক্স রয়েছে। কিন্তু প্রোগ্রামটিতে ০ থেকে ৩ পর্যন্ত ইনডেক্স এক্সেস করা হয়েছে। প্রোগ্রামটিতে যদিও কোন সিন্ট্যাক্স এরর নেই তবুও এই প্রোগ্রামটি রান করানো হলে কনসোলে নিচের মত একটি মেসেজ ডিসপ্লে হবে।

2014-06-05 23:14:01.320 restaurant[598:303] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 3 beyond bounds [0 .. 2]'
*** First throw call stack:
(
	0   CoreFoundation                      0x00007fff9366641c __exceptionPreprocess + 172
	1   libobjc.A.dylib                     0x00007fff8e791e75 objc_exception_throw + 43
	2   CoreFoundation                      0x00007fff935521df -[__NSArrayI objectAtIndex:] + 175
	3   restaurant                          0x0000000100001798 main + 376
	4   libdyld.dylib                       0x00007fff8a1405fd start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

প্রোগ্রামটি রান করলে এই এক্সেপশনটি থ্রো হয় এবং তারপর প্রোগ্রামটি ক্র্যাশ করে। কিভাবে হল? menuList এ তিনটি খাবারের নাম আছে যাদের ইনডেক্স যথাক্রমে ০, ১, ২। প্রোগ্রামটি কম্পাইল করলে কোন রকম এরর বা অন্য কোন ধরনের অস্বাভাবিক ঘটনা ঘটে না। কিন্তু কম্পাইলেশনের পর রান করালে শেষলাইনটি এক্সিকিউশনের সময় menuList[3] দিয়ে menuList এর ৩ নং ইনডেক্সের ভ্যালু এক্সেস করা হয়, তখনই এক্সেপশন (ব্যতিক্রম) ঘটে এবং প্রোগ্রামটি ক্র্যাশ করে কারন menuList অ্যারেতে ০-২ এই তিনটি মাত্র ইনডেক্সই আছে।

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

অন্যান্য হাই লেভেল প্রোগ্রামিং ল্যাঙ্গুয়েজের মতই অবজেকটিভ-সি তেও try-catch-finally প্যাটার্নে এক্সেপশন হ্যান্ডেল করা হয়। প্রথমেই কোডের যেসব লাইনে এক্সেপশন হতে পারে সেগুলোকে @try ব্লকের ভেতরে লেখা হয়। যদি কোন এক্সেপশন ঘটে তাহলে @catch ব্লকে এক্সেপশনের ধরন জেনে এক্সেপশনটিকে হ্যান্ডেল করতে হয়। অবশেষে @finally ব্লকের কোড গুলো এক্সিকিউট করা হয়। এক্সেপশন হোক আর না হোক @finally ব্লক এক্সিকিউট হবেই।

// main.m

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
    
        // menuList of the restaurant
        NSArray *menuList = @[@"Vegetable Rice", @"Chicken Toast", @"Thai Soup"];
        
        @try{
          // write codes where exception can be thrown
          NSLog(@"4th Item Name is %@",  menuList[3]);
        }
        @catch(NSException *theException){
            // exception occurred. Lets handle this exception
            NSLog(@"An Exception named %@ has occurred@",  theException.name);
            NSLog(@"Some more details about the exception : %@",  theException.reason);
        }
        @finally{
            NSLog(@"Continues without crashing the application");
        }
        
        NSLog(@"This is being displayed. That means this application didn't crash.");
    }
    return 0;
}

উপরের main.m কে রান করলে @try ব্লকে menuList এর ৪র্থ আইটেম এক্সেস করার সাথে সাথেই এক্সেপশন থ্রো হয়। @catch ব্লকে NSException এর *theException এ এক্সেপশনটি অ্যাসাইন হয়। NSException ক্লাসের অবজেক্ট theException এর প্রোপার্টিগুলো name, reason, userInfo তে এক্সেপশনটি সম্পর্কে তথ্য পাওয়া যাচ্ছে।

রিয়েল লাইফ অ্যাপ্লিকেশনগুলো তে @catch ব্লকে সাধারনত এক্সেপশনের name ও reason থেকে তথ্য নিয়ে সমস্যার সমাধান করে অথবা ইউজারকে সহজবোধ্য এরর মেসেজ দিয়ে প্রোগ্রামটি কে নরমালি এক্সিট/কন্টিনিউ করা হয়।

অবজেকটিভ-সি এর এক্সেপশন হ্যান্ডেলিং খুব বেশী ইফিশিয়েন্ট না হওয়ায় @try/@catch ব্লক ব্যবহার না করে যদি সাধারন If স্টেইটমেন্ট দিয়ে চেক করে সমস্যা বাইপাস করা যায় তাহলে সেটা করাই ভাল। একান্তই যদি দরকার পড়ে সেক্ষেত্রে উপরের মত @catch ব্লকে ইউজার কে এক্সেপশনের সহজবোধ্য এরর মেসেজ দিয়ে প্রোগ্রামটি এক্সিট করে দেওয়া যেতে পারে।

// main.m

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
    
        // menuList of the restaurant
        NSArray *menuList = @[@"Vegetable Rice", @"Chicken Toast", @"Thai Soup"];
        
        int selectedIndex = 3;
        
        if(selectedIndex < [menuList count]){
            NSLog(@"4th Item Name is %@",  menuList[selectedIndex]);
        }
        else
        {
            //Exception is avoided
        }
    }
    return 0;
}

এই প্রোগ্রামটিতে শুরুতেই selectedIndex এর ভ্যালু চেক করে নেওয়া হচ্ছে। যদি selectedIndex টি menuList এর count এর চেয়ে ছোট হয় তাহলে ওই ইনডেক্সের ভ্যালু এক্সেস করা হচ্ছে। selectedIndex এর ভ্যালু যদি menuList এর count এর সমান বা বড় হয় তাহলে ওই ইনডেক্সের ভ্যালু এক্সেস না করে লাইনটিকে বাইপাস করা হচ্ছে।

বিল্ট-ইন এক্সেপশন (Built-in Exceptions) ঃ
স্ট্যান্ডার্ড iOS ও OS X ফ্রেমওয়ার্ক এ অনেকগুলো বিল্ট-ইন এক্সেপশন রয়েছে যেগুলো দিয়ে মোটামুটি সবরকম এক্সেপশন @catch ব্লকে ধরা যায়। সবচেয়ে বেশী ব্যবহৃত এক্সেপশন গুলো সম্পর্কে নিচে ২-১ লাইন লেখা হলঃ

  • NSRangeException ঃ অ্যারে বা কালেকশনের বাইরের ইনডেক্সের ইলিমেন্ট এক্সেস করলে NSRangeException থ্রো হয়।
  • NSInvalidArgumentException ঃ মেথডে ইনভ্যালিড আরগুমেন্ট পাঠানো হলে NSInvalidArgumentException থ্রো হয়।
  • NSInternalInconsistencyException ঃ ইন্টারনালী যদি কোন অস্বাভাবিক কিছু ঘটে যা প্রোগ্রাম ক্র্যাশ করায় তখন NSInvalidArgumentException হয়।
  • NSGenericException ঃ যখন কোন স্পেসিফিক এক্সেপশন না ধরে জেনেরিক এক্সেপশন ধরতে হয় তখন NSGenericException ক্লাসের অবজেক্ট দিয়ে এক্সেপশনটি ধরা হয়। অর্থাত যেকোন কারনেই এক্সেপশন থ্রো হউক না কেন NSGenericException থ্রো হয়।

খেয়াল করুন যে এই সব এক্সেপশন গুলোর ভ্যালু স্ট্রিং। এদের NSException ক্লাসের সাবক্লাস ভাবার দরকার নেই। তাই কোন স্পেসিফিক এক্সেপশন পেতে চাইলে name প্রোপার্টি চেক করতে হবে।

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

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        // menuList of the restaurant
        NSArray *menuList = @[@"Vegetable Rice", @"Chicken Toast", @"Thai Soup"];
        
        @try{
            // write codes where exception can be thrown
            NSLog(@"4th Item Name is %@",  menuList[3]);
        }
        @catch(NSException *theException){
            // exception occured. Lets handle this exception
           if(theException.name == NSRangeException)
               NSLog(@"NSRangeException Exception is caught.");
            
        }
        @finally{
            NSLog(@"Continues without crashing the application");
        }
        
        NSLog(@"This is being displayed. That means this application didnt crashed.");
    }
    return 0;
}

কাস্টম এক্সেপশন (Custom Exceptions) ঃ
@throw ডিরেক্টিভ দিয়ে সহজেই কাস্টম এক্সেপশন থ্রো করানো যায়। যেখানে এক্সেপশন থ্রো হবে সেখানে NSException ক্লাসের ইন্স্ট্যান্স বানিয়ে exceptionWithName:reason:userInfo: ফ্যাক্টরী মেথড দিয়ে কাস্টম এক্সেপশন ইনস্ট্যান্স বানানো যায়। বোঝার জন্য নিচের উদাহরনটি দেখিঃ

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

NSString *getRandomItemFromMenuList(NSArray *menuList) {
    int max = (int)[menuList count];
    if (max == 0) {
        NSException *e = [NSException
                          exceptionWithName:@"EmptyMenuListException"
                          reason:@"*** The list has no food!"
                          userInfo:nil];
        @throw e;
    }
    int randomIndex = arc4random_uniform(max);
    return menuList[randomIndex];
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        @try {
            NSString *foodItem = getRandomItemFromMenuList(@[]);
            NSLog(@"The selected food is: %@", foodItem);
        } @catch(NSException *theException) {
            if (theException.name == @"EmptyMenuListException") {
                NSLog(@"Caught an EmptyMenuListException");
            } else {
                NSLog(@"Ignored a %@ exception", theException);
                @throw;
            }
        }
    }    return 0;
}

@throw ডিরেক্টিভ খুবই এক্সপেনসিভ অপারেশন। এই অপারেশনটি এক্সিকিউট করতে অপারেটিং সিস্টেম এর প্রচুর রিসোর্স খরচ হয়। তাই @throw ডিরেক্টিভ ব্যবহার না করে অবজেকটিভ সি এর ন্যাটিভ এক্সেপশন গুলো ব্যবহার করাই উত্তম।

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

NSException ক্লাসের মতই NSError ক্লাসের ইনস্ট্যান্স দিয়ে ফেইল হওয়া অপারেশন তথা এরর সম্পর্কে যাবতীয় তথ্য পাওয়া যায়। NSError ক্লাসের প্রধান প্রোপার্টিগুলো নিচে দেওয়া হলঃ

  • domain (NSString) ঃ সব এরর গুলো কে কতগুলো ডোমেইনে ভাগ করা হয়েছে। এই ডোমেইন দিয়ে এরর গুলোকে সুন্দরভাবে hierarchy তে সাজানো হয়েছে।
  • code (NSInteger) ঃ code হল একটি নির্দিষ্ট ডোমেইনে এররের ইউনিক আইডি (ID)
  • userInfo (NSDictionary) ঃ NSException ক্লাসের মতই userInfo এরর সম্পর্কে অতিরিক্ত তথ্য রাখে

আগেই বলেছি যে userInfo তে তথ্যগুলো কি-ভ্যালু পেয়ার (key-value pair) হিসেবে থাকে। আবার NSException এর তুলনায় NSError এ বেশী সংখ্যক তথ্য থাকে। গুরুত্বপুর্ন কয়েকটি কি (key) হল NSLocalizedDescriptionKey, NSLocalizedFailureReasonErrorKey, NSUnderlyingErrorKey। মজার ব্যপার হল এররের ধরন অনুযায়ী userInfo ডিকশনারীর কি(key) গুলো কমবেশী হয়। যেমন ফাইল লোড করতে গিয়ে যে এরর হয় তাতে NSFilePathErrorKey নামে একটি কি(key) থাকে যাতে ফাইলটির লোকেশন থাকে।

এরর হ্যান্ডেলিং (Handling Errors) ঃ
এরর হ্যান্ডেল করার জন্য এক্সেপশনের মত @try-@catch ব্লক বা আলাদা কিছু লিখতে হয় না। যেসব মেথড বা ফাংশনে এরর হতে পারে সেসবে একটি বাড়তি আর্গুমেন্ট হিসেবে NSError ক্লাসের অবজেক্ট পাঠানো হয়। মেথড অথবা ফাংশনটি যদি কোন কারনে ফেইল করে (কোন এরর হয়) তাহলে NO অথবা nil রিটার্ন করে এবং NSError ক্লাসের এই অবজেক্টটিতে এরর ডিটেইলস অ্যাসাইন হয়। কিন্তু যদি মেথড/ফাংশনটি সাকসেসফুলি এক্সিকিউট হয় তাহলে এই মেথডটি রিটার্ন টাইপ অনুযায়ী যে ডাটা রিটার্ন করার কথা ছিল তাই রিটার্ন করে।

অবজেক্টিভ সি এর বেশিরভাগ মেথডগুলো আর্গুমেন্ট হিসেবে NSError ক্লাসের অবজেক্টের Indirect রেফারেন্স নিয়ে থাকে। Indirect রেফারেন্স হল মুলত পয়েন্টার যা অন্য পয়েন্টারকে পয়েন্ট করে থাকে। এতে যে সুবিধা পাওয়া যায় তা হল, মেথডটি ওই আর্গুমেন্টটিকে NSError ক্লাসের সম্পুর্ন নতুন একটি ইনস্ট্যান্সে পয়েন্ট করাতে পারে। মেথডের মধ্যে ওই পয়েন্টার যে ইনস্ট্যান্সকে পয়েন্ট করে আছে তার প্রোপার্টিগুলোতে ভ্যালু অ্যাসাইন করা হয়। মেথডের এরর আর্গুমেন্টটি যদি Indirect রেফারেন্স এক্সেপ্ট করে তাহলে নিচের মত দুইবার পয়েন্টার চিহ্ন (double-pointer notation) দিয়ে ইনস্ট্যান্স পাওয়া যায়।

(NSError **)error

শুরুতেই এরর হ্যান্ডেল করার একটি সাদামাটা প্রোগ্রাম দেখা যাক। নিচের main.m ফাইলের মত করে আমাদের main.m ফাইলটি এডিট করি। এ প্রোগ্রামে শুরুতেই path নামের একটি ভ্যারিয়েবলে একটি ফাইলের পাথ দেওয়া হয়েছে। মুলত আমরা এই file.md ফাইলটির ডাটাগুলো পড়তে চাচ্ছি। এরপর NSError ক্লাসের একটি ইনস্ট্যান্স error নেওয়া হল। পরবর্তী লাইনে stringWithContentsOfFile:encoding:error: মেথডকে কিছু আর্গুমেন্ট সহ কল করা হয়েছে। এই মেথডটি অবজেক্টিভ সি এর বিল্টইন মেথড যা প্রথম আর্গুমেন্টের লোকেশন থেকে ফাইল লোড করে ফাইলের ডাটা (NSString টাইপ) রিটার্ন করে। তৃতীয় প্যারামিটারটি NSError ক্লাসের অবজেক্ট যা রেফারেন্স অপারেটর (&) দিয়ে পাঠানো হয়। &error মুলত একটি পয়েন্টার যা NSError ক্লাসের ইনস্ট্যান্স *error কে পয়েন্ট করে থাকবে।

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

int main(int argc, const char * argv[]) {
    
    @autoreleasepool {
    
        NSString *path = @"/path/to/file.md";
        
        NSError *error;
        NSString *content = [NSString stringWithContentsOfFile: path
                                                      encoding: NSUTF8StringEncoding
                                                         error: &error];
        
        if (content == nil) {
            // Method failed
            NSLog(@"Error loading file %@!", path);
            NSLog(@"Domain: %@", [error domain]);
            NSLog(@"Error Code: %ld", [error code]);
            NSLog(@"Description: %@", [error localizedDescription]);
            NSLog(@"Reason: %@", [error localizedFailureReason]);
            NSLog(@"Recovery procedure: %@",[error localizedRecoverySuggestion]);
        } else {
            // Method succeeded
            NSLog(@"Date Loaded from file: %@", content);
        }
    }
    return 0;
}

file.md ফাইলটি যদি ওই লোকেশনে না থাকে তাহলে stringWithContentsOfFile মেথডটি nil বা NO রিটার্ন করে এবং error অবজেক্টে এররের ডিটেইলস অ্যাসাইন হয়। অন্যথায় মেথডটি ফাইলের কনটেন্ট রিড করে তা রিটার্ন করে যা NSString টাইপ content ভ্যারিয়েবলে অ্যাসাইন হয়। এরপর content এর ভ্যালু চেক করে যদি NO বা nil হয় তাহলে error অবজেক্টের প্রোপার্টিগুলো code, domain, localizedDescription, localizedFailureReason ইত্যাদি এক্সেস করে এরর সম্পর্কে যাবতীয় তথ্য পাওয়া যায়।

যদি এমন হয় যে আপনি শুধু জানতে চাচ্ছেন যে এরর হয়েছে কিনা; এররের কারন না জানলেও চলবে সেক্ষেত্রে error ইনস্ট্যান্সের জন্য শুধুমাত্র NULL পাঠালেই চলবে। নিচের কোডটুকু খেয়াল করিঃ

        NSString *content = [NSString stringWithContentsOfFile:fileToLoad
                                                      encoding:NSUTF8StringEncoding
                                                         error: NULL];
        
        if (content == nil) {
           // error occured  
        } else {
            // Method succeeded
           }

বিল্ট-ইন এরর (Built-in Errors) ঃ
NSException ক্লাসের মত NSError ক্লাসের ও কিছু বিল্ট-ইন এরর ডোমেইন রয়েছে যা দিয়ে এরর গুলো কে রিপ্রেজেন্ট করা যায়। প্রধান কয়েকটি বিল্ট-ইন এরর ডোমেইন এর নাম নিচে দেওয়া হলঃ

  • NSMachErrorDomain
  • NSPOSIXErrorDomain
  • NSOSStatusErrorDomain
  • NSCocoaErrorDomain

আমাদের প্রোগ্রামগুলোতে সবচেয়ে বেশী যে এরর গুলো ঘটবে সেগুলো NSCocoaErrorDomain এর অন্তর্ভুক্ত। তারপরও চাইলে আরো লো-লেভেলের এরর ডোমেইনের এরর ইনফরমেশন পাওয়া যাবে। যেমন আমাদের উপরের main.m ফাইলে যদি নিচের লাইনটি লেখি তাহলে NSPOSIXErrorDomain এর এরর ইনফরমেশন পাওয়া যাবে।

 NSLog(@"Lower Level Domain Error : %@",error.userInfo[NSUnderlyingErrorKey]);

এই লাইনটির আউটপুট হবে
Lower Level Domain Error : Error Domain=NSPOSIXErrorDomain Code=2 “The operation couldn’t be completed. No such file or directory”

আগেই বলেছি যে সকল এরর গুলো কতগুলো ডোমেইন এ ভাগ করা হয়েছে। প্রত্যেক ডোমেইনের অন্তর্গত সকল এররের নির্দিষ্ট ও ইউনিক কোড (code) থাকে যা দিয়ে স্পেসিফিক এরর ইনফরমেশন পাওয়া যায়। Foundation Constants Reference ডকুমেন্টটিতে কিছু enum দিয়ে NSCocoaErrorDomain ডোমেইনের প্রায় সকল কোডের (code) বর্ননা দেওয়া আছে। উদাহরন স্বরুপ নিচের প্রোগ্রামে দেখা যাচ্ছে NSCocoaErrorDomain এর NSFileReadNoSuchFileError নামক কোডের এরর খোজার জন্য প্রোগ্রামটি ওত পেতে বসে আছে।

if (content == nil) {
    if ([error.domain isEqualToString:@"NSCocoaErrorDomain"] &&
        error.code == NSFileReadNoSuchFileError) {
        NSLog(@"That file doesn't exist!");
        NSLog(@"Path: %@", [[error userInfo] objectForKey:NSFilePathErrorKey]);
    } else {
        NSLog(@"Some other kind of read occurred");
    }
}

কাস্টম এরর (Custom Errors) ঃ
বড় সাইজের IOS ও OS X এর অ্যাপ্লিকেশনে বিভিন্ন মেথডে বিভিন্ন ধরনের এরর হওয়ার সম্ভাবনা থাকে যা সংখ্যায় খুব কম নয়। একারনে প্রোগ্রামারের সুবিধার্থে ও ইউজারের কাছে আরও সহজবোধ্য মেসেজ পাঠানোর উদ্দেশ্যে কাস্টম এরর বানানো হয়। বেস্ট প্র্যাকটিস হিসেবে সব এররগুলো কে একটি আলাদা হেডার ফাইলে (For Ex- RestaurantErrors.h) লেখা হয়। পরবর্তীতে প্রোগ্রামের যেসব ইমপ্লিমেনটেশন ফাইলে এই কাস্টম এরর গুলো ব্যবহার করা হবে সেখানে ইমপোর্ট করে নিলেই হবে।

//RestaurantErrors.h
NSString *RestaurantErrorDomain = @"net.Nuhil.Restaurant.ErrorDomain";

enum {
    MenuListNotLoadedError,
    MenuListEmptyError,
    RestaurantInternalError
};

কাস্টম এরর ডোমেইনের নাম যেকোন কিছুই হতে পারে, তবে CompanyName.ProjectOrFrameWorkName.ErrorDomain রাখাটাই বেস্ট প্র্যাকটিস। এরর কোড কনস্ট্যান্ট গুলো কে enum এর মধ্যে ডিফাইন করা হয়।

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

NSString *getFoodTitleWithId( int foodId, NSError **error) {
   
    NSArray *Food = @[];
    
    int max = [Food count];
    
    if (max == 0) {
        if (error != NULL) {
            NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"MenuList"
                                       " Currently Empty."};
            
            *error = [NSError errorWithDomain: RestaurantErrorDomain
                                         code: MenuListEmptyError
                                     userInfo: userInfo];
        }
        return nil;
    }
    return Food[foodId];
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int searchFor = 2;
        NSError *error;
        NSString *title = getFoodTitleWithId(searchFor, &error);
        
        if (title == nil) {
            // If Failed
            NSLog(@"Title could not be found");
            NSLog(@"Domain: %@", error.domain);
            NSLog(@"Error Code: %ld", error.code);
            NSLog(@"Description: %@", [error localizedDescription]);
            
        } else {
            // Succeeded
            NSLog(@"Selected Food Title Found!");
            NSLog(@"%@", title);
        }
    }
    return 0;
}

main.m এর main মেথড এ দেখা যাচ্ছে যে আরগুমেন্ট হিসেবে একটি ইনডেক্স বা আইডি (searchFor) এবং NSError ক্লাসের একটি Indirect রেফারেন্স &error সহ getFoodTitleWithId কে কল করা হযেছে। মেথডটিতে &error পাঠানোর উদ্দেশ্য হল যদি মেথডের ভেতর কোন এরর হয় তাহলে এররের প্রোপার্টিগুলোর ভ্যালু যাতে এই error ইনস্ট্যান্স এ অ্যাসাইন হয়। যদি ২য় আরগুমেন্টে NULL পাঠানো হত তাহলে এরর সম্পর্কিত কোন ইনফরমেশন আর পাওয়া যেত না। যদি এরর হত তাহলে মেথডটি শুধুমাত্র NO অথবা nil রিটার্ন করত।

getFoodTitleWithId মেথডে FoodId তে 2 এবং NSArray ক্লাসের Indirect রেফারেন্স প্যারামিটার হিসেবে এসেছে। মেথডের শুরুতেই NSArray টাইপ একটি ভ্যারিয়েবল ডিক্লেয়ার করা হয়েছে যাতে আইটেম সংখ্যা শুন্য। অর্থাত পরের লাইনে max এর ভ্যালু শুন্য হবে। এপর্যায়ে আমরা চাচ্ছি যেহেতু Food লিস্টটিতে কোন আইটেম নেই তাই একটি কাস্টম এরর থ্রো করাব। তাই যখন max এর ভ্যালু শুন্য এবং NSError এর Indirect রেফারেন্সটি NULL নাহয় তখন কাস্টম এররটির প্রোপার্টিগুলোর ভ্যালু পপুলেট করা হচ্ছে এবং অবশেষে nil রিটার্ন করে দেওয়া হয়েছে।

উপরের প্রোগ্রামটি রান করালে নিচের মত আউটপুট আসবে।

2014-06-10 00:56:19.817 restaurant[904:303] Title could not be found
2014-06-10 00:56:19.819 restaurant[904:303] Domain: net.Nuhil.Restaurant.ErrorDomain
2014-06-10 00:56:19.819 restaurant[904:303] Error Code: 1
2014-06-10 00:56:19.820 restaurant[904:303] Description: MenuList Currently Empty.
Program ended with exit code: 0

RestaurantErrorDomain এ এরর কোডগুলো যেহেতু enum টাইপ সেহেতু এরর কোডগুলোর ভ্যালুগুলো শুন্য থেকে শুরু করে ২ পর্যন্ত। তাই MenuListEmptyError এর ভ্যালু ১।

পরিশিষ্ঠঃ
এই চ্যাপ্টারের মাধ্যমেই আমাদের ব্যাসিক ওব্জেক্টিভ-সি লার্নিং সেকশন শেষ হয়ে যাচ্ছে। এর পরের সেকশনে আসছে রিয়াল লাইফ গ্রাফিক্যাল অ্যাপ্লিকেশন তৈরি সম্পর্কিত ১০টি চ্যাপ্টার। উক্ত সেকশন শেষ হবার পর আসবে ব্যাসিক সুইফ্ট ল্যাঙ্গুয়েজ লার্নিং সেকশন।

অনেকেই হয়ত ভেবে থাকতে পারেন যে, Apple যেহেতু iOS অ্যাপ ডেভেলপমেন্ট এর জন্য তাদের নতুন ল্যাঙ্গুয়েজ ঘোষণা করেছে তাহলে আর অবজেক্টিভ শিখে কি লাভ। কিন্তু এ ধারনা একদম ভুল। প্রথমত, এখন পর্যন্ত অ্যাপ স্টোরে ১০ লাখেরও বেশি অ্যাপ জীবন্ত আছে যেগুলো অব্জেক্টিভ-সি তে করা। সেই অ্যাপ গুলোর মেইন্টেইনেন্স, আপডেট, বাগ ফিক্সিং ইত্যাদির জন্য আরও সামনে ৬/৭ বছর iOS এবং অব্জেক্টিভ-সি এর ব্যবহার চলবেই। দ্বিতীয়ত, তাদের নতুন ঘোষণা মতে, একটি প্রজেক্টে অথবা অ্যাপ্লিকেশনে একি সাথে অবজেক্টিভ-সি এবং সুইফ্ট ল্যাঙ্গুয়েজ কোড থাকতে পারে এবং রান হতে পারে। অর্থাৎ তারা চাচ্ছে, আস্তে আস্তে অব্জেক্টিভ-সি এর জায়গাটা কমে আসুক, একবারে না। তৃতীয়ত, অনেক ডেভেলপার বা কোম্পানি হয়ত চাইতেই পারে যে তাদের সামনের অ্যাপ্লিকেশনগুলো তারা অবেজক্টিভ-সি দিয়েই করবে কারন সুইফ্ট -এ দক্ষ ডেভেলপার এই মুহূর্তে হয়ত তারা ব্যবস্থা করতে পারবেন না। চতুর্থত, হাজার হাজার থার্ড পার্টি লাইব্রেরী, ফ্রেমওয়ার্কও কিন্তু অব্জেক্টীভ-সি তে করা যেগুলো হয়ত আপনি আপনার নেক্সট প্রজেক্টে ব্যবহার করবেন বলে ভেবে রেখেছেন। অন্যদিকে, অনেকেই হয়ত চাইবেন তাদের পরবর্তী প্রজেক্টটি নতুন ল্যাঙ্গুয়েজ দিয়ে করতে। অর্থাৎ আপনি যদি ফ্রেশ ভাবে iOS অ্যাপ ডেভেলপমেন্ট শুরু করতে চান তাহলে শুধুমাত্র সুইফ্ট শেখা শুরু করতে পারেন কিন্তু যদি ক্যারিয়ার হিসেবে দেখতে চান তাহলে আপনাকে দুটো ল্যাঙ্গুয়েজ সম্পর্কে ধারনা রাখতেই হবে।

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

Standard

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

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

সাধারণত, একটি অবজেক্টের প্রোপার্টিগুলো অন্য আরেকটি অবজেক্টকে তাদের অবস্থা পরিবর্তন এবং যাচাই করতে দেয়। কিন্ত ভালভাবে ডিজাইন করা কোন অবজেক্ট অরিয়েনটেড প্রোগ্রামে অবজেক্টের ইন্টারনাল অবস্থা জানা বা পরিবর্তন করা সহজ নয়। এর জন্য প্রয়োজন Accessor Methods তথা getters এবং setters।

Objective C তে @property এর কাজ হল অটোমেটিক্যালি এই Accessor method গুলো জেনারেট করে সহজে প্রোপার্টি তৈরী এবং কনফিগার করার ব্যবস্থা করা। যেসব প্রোপার্টি গুলো Public হবে শুধুমাত্র সেগুলোর জন্যই @property ডিরেকটিভ ব্যবহার করা হয়। ফলে সহজেই সিমান্টিক লেভেলে প্রোপার্টির behavior ঠিক করে দেওয়া যায় এবং এটা একই সাথে ওই প্রোপার্টির ইম্পলিমেন্টেশন ডিটেইলসও ম্যানেজ করে।

@property ডিরেকটিভঃ
প্রথমেই দেখা যাক @property ডিরেকটিভ ব্যবহার করলে কি ঘটনা ঘটে। গত অধ্যায়ের সাথে মিল রেখে একটি Food ক্লাসের জন্য একটি সহজ ইন্টারফেস এবং ইম্পলিমেন্টেশন লেখা যাক।

//  Food.h

#import <Foundation/Foundation.h>

@interface Food : NSObject

@property NSString *item;

@end

 

//  Food.m

#import "Food.h"

@implementation Food

@end

Food ইন্টারফেসের একটি প্রোপার্টি item যার ডাটাটাইপ NSString। যেহেতু অবজেকটিভ সি তে সকল ভ্যারিয়েবলকে পয়েন্টার হিসেবে ব্যবহার করা হয় তাই item এর আগে পয়েন্টার চিহ্ন ব্যবহার করা হয়েছে। লক্ষনীয় ব্যপার হল এখানে item ডিক্লেয়ার করার আগে @property ডিরেকটিভ লেখা আছে।

কোন ভ্যারিয়েবলকে @property ডিরেকটিভ হিসেবে ডিক্লেয়ার করা হলে, তার জন্য অটোমেটিক্যালি Accessor methods জেনারেট হয়ে যায় এবং নিজ ক্লাসের ইন্টারফেস ও ইমপ্লিমেন্টেশনে থাকা অন্যান্য মেথড গুলোর মতই ওই অদৃশ্য গেটার এবং সেটার মেথড গুলোকে কল করা যায়। item প্রোপার্টির জন্য আসলে নিচের মত গেটার এবং সেটার মেথড তৈরি হয়ে গেছে যেগুলো আমরা একটু পরেই মুল প্রোগ্রামে ব্যবহার করতে পারবো।
বিঃ দ্রঃ কাস্টম সেটার ও গেটার তৈরির করার জন্য Food.m -এ এই গেটার এবং সেটারকে ওভাররাইডও করা যায়। তবে কাস্টম সেটার ও গেটার তৈরির জন্য @synthesize ডিরেকটিভ আবশ্যক।

- (NSString *)item {
    return item;
}
- (void)setItem:(NSString *)newValue {
    item = newValue;
}

এবার আমাদের main.m ফাইলকে নিচের মত করে আপডেট করুন।

// main.m

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

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

        Food *food = [[Food alloc] init];
        food.item = @"A bengali dish!"; // Under hood: [food setItem: @"A bengali dish!"]
        
        NSLog(@"Eating a %@", food.item); // Under hood: [food item]
        
    }
    return 0;
}

ডট নোটেশন দিয়ে প্রোপার্টি এক্সেস করার সময় মুলত ব্যাকএন্ডে accessor মেথড গুলোতেই ট্রানস্লেটেড হয়। ফলে food.item এ কোন স্ট্রিং এসাইন করলে setItem: মেথড কল হয় এবং food.item দিয়ে ডাটা চাইলে item: মেথডটাই কল হয়।

এক্সেসর মেথডগুলোর বিহেভিয়র পরিবর্তন করার জন্য @property ডিরেকটিভ এর পর প্যারেনথেসিস () এর ভিতরে বিহেভিয়র এর ধরন তথা এট্রিবিউট সেট করা যায়। এই চাপ্টারের বাকি অংশে বিভিন্ন রকম অ্যাট্রিবিউট নিয়ে আলোচনা হবে।

getter= এবং setter= অ্যাট্রিবিউটস্ঃ
@property ডিরেকটিভ এর ডিফল্ট নেমিং কনভেনশন পছন্দ না হলে, আমরা getter= এবং setter= ব্যবহার করে getter এবং setter মেথড গুলোর নাম পরিবর্তন করতে পারি নিচের মত করে। উল্লেখ্য, গেটার/সেটারকে কাস্টম নাম দেয়ার একটা সাধারণ সিচুয়েশন হচ্ছে যখন কোন বুলিয়ান টাইপ প্রোপার্টির ব্যবহার চলে আসে এবং সেগুলোকে আরও হিউম্যান রিডেবল করার জন্য।

@property (getter=isOpen) BOOL open;

এ অবস্থায় জেনারেট হওয়া এক্সেসর মেথড গুলোকে isOpen এবং setOpen দিয়ে কল করা হবে/যাবে। আসুন আমাদের Food.h, Food.m এবং main.m কে নিচের মত করে সাজাই,

// Food.h

#import <Foundation/Foundation.h>

@interface Food : NSObject

@property (getter=isOpen) BOOL open;

@end
// Food.m

#import "Food.h"

@implementation Food


@end
// main.m

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

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

        Food *place = [[Food alloc] init];
        place.open = NO; // Under hood: [food setOpen]
        
        // NSLog(@"Is the restaurant open?: %hhd", [place open]); // Error: No method exists
        
        NSLog(@"Is the restaurant open?: %hhd", [place isOpen]); // Works!
        
        NSLog(@"Is the restaurant open?: %hhd", place.open);  // Works! Under hood: [place isOpen]
        
    }
    return 0;
}

খেয়াল করুন এখন কিন্তু আর গেটারের ব্যাকএন্ড স্টাইল [place open] কাজ করবে না বরং [place isOpen] কাজ করবে যেখানে isOpen কে গেটার হিসেবে বলে দিয়েছি আমরা। আবার, এখনো কিন্তু পাবলিক প্রোপার্টিগুলোকে শুধু প্রোপার্টির নাম দিয়েও এক্সেস করা যাচ্ছে।
বিঃ দ্রঃ শুধুমাত্র এই অ্যাট্রিবিউট দুটি আর্গুমেন্ট এক্সেপ্ট করে। অন্য সকল অ্যাট্রিবিউটগুলো বুলিয়ান ফ্ল্যাগ।

রিডঅনলি (readonly) অ্যাট্রিবিউটঃ
ক্লাসের কোন প্রোপার্টিকে রিড অনলি (শুধু ভ্যালু রিড করা যাবে, নতুন করে সেট করা যাবে না) করার সহজ উপায় হল এই প্রোপার্টির জন্য readonly অ্যাট্রিবিউট সেট করা। কোন প্রোপার্টিকে readonly করলে, প্রোপার্টিটির setter মেথড থাকে না এবং ডট নোটেশন ব্যবহার করে ভ্যালু অ্যাসাইন করা যায় না। নিচের উদাহরনটি দেখলেই পরিস্কার হয়ে যাবে।

//  Food.h

#import <Foundation/Foundation.h>

@interface Food : NSObject

@property (getter=isOpen, readonly) BOOL open;

@end
//  Food.m

#import "Food.h"

@implementation Food


@end
// main.m

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

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

        Food *place = [[Food alloc] init];
        place.open = YES; // Error: can't assign to readonly property
        
    }
    return 0;
}

এ অবস্থায় Xcode -ই আপনাকে আটকিয়ে দিবে নিচের মত,
Screen Shot 2014-05-20 at 6.12.28 PM

তবে হ্যাঁ, আমরা ইন্সট্যান্স মেথড ব্যবহার করে ইন্টারনালি এই open নামক রিডঅনলি প্রোপার্টিরটার ভ্যালু পরিবর্তন করতে পারবো। এই সিচুয়েশন ট্রাই করার জন্য নিচে যথাক্রমে ইন্টারফেস, ইমপ্লিমেন্টেশন ও মেইন ফাইলটি দেওয়া হল:

//  Food.h

#import <Foundation/Foundation.h>

@interface Food : NSObject

@property (getter=isOpen, readonly) BOOL open;
-(void)openTheRestaurant;

@end
//  Food.m

#import "Food.h"

@implementation Food 

-(void)openTheRestaurant
{
    // N.B. We can use _open directly, cause @property also creates an 
    // instance variable for us!
    _open = YES; 
}

@end
// main.m

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

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

        Food *place = [[Food alloc] init];
        [place openTheRestaurant]; // Setting the new value by this imethod

        NSLog(@"Is the restaurant open?: %hhd", place.open);
    }
    return 0;
}

এটি রান করালে কনসোলে Is the restaurant open?:1 দেখতে পাবেন অর্থাৎ ওই রিডঅনলি বুলিয়ান প্রোপার্টিটার ভ্যালু চেঞ্জ করা গেছে যেটা বাই ডিফল্ট 0 থাকে।

ননঅ্যাটমিক (nonatomic) অ্যাট্রিবিউটঃ
মাল্টিথ্রেডেড এনভাইরনমেন্টে (যখন কোন অ্যাপ্লিকেশনে একাধিক থ্রেড থাকে) getter এবং setter মেথড গুলো একাধিকবার কল হতে পারে। অর্থাত অন্য কোন অপারেশন বর্তমানে এক্সিকিউট হচ্ছে এমন কোন getter/setter মেথডের এক্সিকিউশনে ইন্টারাপ্ট করে রেজাল্টে প্রভাব ফেলতে পারে। Atomic প্রোপার্টি অবজেক্টকে লক করে দেয় যাতে করে getter/setter মেথড গুলো কমপ্লিট ভ্যালু নিয়ে কাজ করতে পারে।

@property ডিরেকটিভ দিয়ে ডিক্লেয়ার করা প্রোপার্টি বাই ডিফল্ট Atomic হয়। যা আমাদের মাথার উপর থেকে ম্যানুয়ালী Atomicity নিশ্চিত করার বোঝা কমিয়ে দিয়েছে। কিন্তু যদি আপনার অ্যাপ্লিকেশনটি একটিমাত্র থ্রেড নিয়ে হয় অথবা আপনি নিজের মত করে Thread-Safety ইমপ্লেমেন্ট করে থাকেন, তাহলে প্রোপার্টিটিকে nonatomic হিসেবে ডিক্লেয়ার করলেই চলে।

@property (nonatomic) NSString *item;

আরও একটি উল্লেখযোগ্য ব্যপার হল, Atomic প্রোপার্টিগুলোর getter এবং setter দুটি মেথডই অটো-জেনারেটেড হবে অথবা দুটি মেথডই ইউজার ডিফাইন্ড হবে। কিন্তু nonatomic প্রোপার্টি গুলোর জন্য কোন একটি ইউজার ডিফাইন্ড এবং অন্যটি অটো জেনারেটেড এরকম মিক্স হতে পারে।

মেমরী ম্যানেজমেন্ট (Memory Management)ঃ 
অবজেক্ট অরিয়েন্টেড ল্যাঙ্গুয়েজে, অবজেক্ট গুলো কম্পিউটারের মেমরী লোকেশনে স্টোর করা হয়। এখনো পর্যন্ত মেমরীই হল দুর্লভ রিসোর্স বিশেষ করে মোবাইল ডিভাইস গুলোর জন্য। মেমরী ম্যানেজমেন্টের মুল লক্ষ্যই হল কম্পিউটার বা মোবাইলের মেমরীর সঠিক ব্যবহার করা। অ্যাপ্লিকেশনটি অপ্রয়োজনীয় কোন মেমরী যাতে ব্যবহার করতে না পারে সেটা নিশ্চিত করাই মেমরী ম্যানেজমেন্টের কাজ।

বেশীরভাগ ল্যাঙ্গুয়েজেই garbage collection দিয়েই মেমরী ম্যানেজমেন্ট করা হয়। কিন্তু অবজেকটিভ সি (Objective C) অবজেক্ট ওনারশিপ (Object Ownership) দিয়ে মেমরী ম্যানেজ করে যা garbage collection এর চেয়ে অনেকবেশী ইফিশিয়েন্ট। যখন কোন প্রোগ্রাম কোন অবজেক্টের সাথে ইন্টারঅ্যাক্ট শুরু করে তখনই প্রোগ্রামটিকে এই অবজেক্টের ওনার (owner) বলা হয়। আবার যখন প্রোগ্রামটির কাজ শেষ হয়ে যায় অথবা প্রোগ্রামটির আর অবজেক্টের দরকার থাকে না তখন অবজেক্টটির owner হিসেবে প্রোগ্রামটি থাকেনা। একটি অবজেক্টের একাধিক owner থাকতে পারে। অর্থাত যখন কোন অবজেক্টের কমপক্ষে একটি ওনার থাকবে তখন বুঝতে হবে অবজেক্টটি ব্যবহার করা হচ্ছে। কোন অবজেক্টের যদি একটিও Owner না থাকে তখন বুঝতে হবে যে এই অবজেক্টের আর কোন কাজ নেই। তাই অপারেটিং সিস্টেম অবজেক্টটিকে ডেস্ট্রয় করে দিয়ে মেমরী ফ্রি করে নেয়।
AUTOMATIC REFERENCE COUNTING এর মাধ্যমে অপারেটিং সিস্টেম নিজে নিজেই মেমরী ম্যানেজমেন্টের কাজ গুলো করে নেয়। এসব নিয়ে আমাদের মাথা গরম করার কোন দরকার নেই।
কিন্তু আমাদেরকে অবশ্যই strong, weak এবং copy অ্যাট্রিবিউটগুলো সম্পর্কে জানতে হবে কারন এই অ্যাট্রিবিউটগুলোই কম্পাইলারকে অবজেক্টের রিলাশনশিপ কেমন হবে তা জানায়।

স্ট্রং (strong) এবং উইক (weak) অ্যাট্রিবিউটঃ
প্রথমেই দেখি কিভাবে একটি স্ট্রং অ্যাট্রিবিউটের প্রোপার্টি ডিক্লেয়ার করা যায়,

@property (nonatomic, strong) NSString *name;

আগেও একবার বলা হয়েছে যে, ARC বা Automatic Reference Counting হচ্ছে একটি স্বয়ংক্রিয় মেমোরি ম্যানেজমেন্ট ব্যবস্থা যার মাধ্যমে সিস্টেম স্বয়ংক্রিয় ভাবে যেকোনো অপ্রয়োজনীয় অবজেক্টের মেমোরি ফ্রি করে। আর এই ফ্রি করার ব্যপারটা সে ঠিক করে রেফারেন্সের নাম্বার (Count) এর উপর। যেটার রেফারেন্স যখন 0 হয়ে যায় তখনি তার মেমোরি ফ্রি/রিলিজ করে দেয়।

উপরে strong অ্যাট্রিবিউট হচ্ছে কোন অবজেক্টের এমন একটি স্ট্রং রেফারেন্স যা তাকে ডিঅ্যালোকেটেড হতে দেয় না। অর্থাৎ তার রেফারেন্স কাউন্ট হয় 0 এর চেয়ে বেশি বা 1, 2 … এরকম। এখানে name কে strong প্রোপার্টি হিসেবে ডিক্লেয়ার করা দুটি অর্থ বহন করেঃ
১। যখন আপনি name এর মধ্যে একটি অবজেক্ট অ্যাসাইন করবেন, তখন সেই অবজেক্টটির রেফারেন্স কাউন্ট বেড়ে যায়।
২। যখন অ্যাসাইন করা অবজেক্টটি যাকে name পয়েন্ট করে সেটাকে আপনি বা সিস্টেম কোনভাবে ডিঅ্যালোকেট করবেন তখনও name এর ভ্যালু আগের মতই থাকবে অর্থাৎ name আসলে এর মধ্যে অ্যাসাইন করা অবজেক্টটির মালিকানা পেয়ে গিয়েছিল; কারন name একটি strong Relationship.

এবার আসুন একটি উদাহরণ দেখি। প্রথমেই আমাদের বর্তমান প্রজেক্টে আরও একটি নতুন ক্লাস (NSObject এর সাব) যুক্ত করে নিন যার নাম Person. ফলে নতুন দুটি ফাইল পেয়ে যাবো আমরা যেগুলোর কোড আপডেট করে নিন নিচের মত,

// Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic) NSString *name;

@end

অর্থাৎ এই নতুন ক্লাসের একটি মাত্র সাধারণ প্রোপার্টি যার নাম name.

// Person.m

#import "Person.h"

@implementation Person

- (NSString *)description {
    return self.name;
}

@end

Person ক্লাসের ইমপ্লেমেন্টেশনে আমরা description নামের একটি ডিফল্ট মেথডকে ওভাররাইড করেছি যার কাজ হল এর name প্রোপার্টিটিকে রিটার্ন করা। অর্থাৎ কোথাও এই ক্লাসের ডাইরেক্ট অবজেক্টকেই ব্যবহার করলে তা পক্ষান্তরে এটার name প্রোপার্টিটিকেই সেখানে হাজির করবে। এটুকু আমরা করছি আমাদের উদাহরণ এর স্বার্থে, description মেথডের ব্যবহার শেখাতে নয়।

এখন নিচের মত করে Food.h ফাইল আপডেট করুন,

// Food.h

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

@interface Food : NSObject

@property (nonatomic) NSString *item;
@property (nonatomic, strong) Person *cook;

@end

এখানে প্রথমে আমরা একটি সাধারণ NSString প্রোপার্টি অ্যাড করেছি এবং তার নিচে একটি Person প্রোপার্টি অ্যাড করেছি এবং সেটার অ্যাট্রিবিউট হিসেবে strong সেট করেছি। অর্থাৎ পরবর্তীতে এই cook এর মধ্যে যখন আমরা কোন অবজেক্ট অ্যাসাইন করব তখন সেই অবজেক্টটির রেফারেন্স কাউন্ট বেড়ে যাবে।

Food এর ইমপ্লেমেন্টেশন একদমই ফাকা আপাতত এই উদাহরণ এর সাপেক্ষে,

// Food.m

#import "Food.h"

@implementation Food


@end

এবার main.m কে নিচের মত আপডেট করুন,

// main.m

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

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

        Person *tomi = [[Person alloc] init];
        tomi.name = @"Tomi Mia";
        
        Food *newDish = [[Food alloc] init];
        newDish.item = @"Halim";
        newDish.cook = tomi;
        
        NSLog(@"%@ is cooking the %@", newDish.cook, newDish.item);
        
    }
    return 0;
}

খেয়াল করুন, প্রথমে আমরা Person ক্লাস ইন্সট্যান্সিয়েট করে tomi অবজেক্টের মাধ্যমে এর (Person এর) name প্রোপার্টিটি সেট করে দিয়েছি। তারপর আমরা Food ক্লাস ইন্সট্যান্সিয়েট করে newDish অবজেক্টের মাধ্যমে এর (Food এর) item প্রোপার্টিটি সেট করে দিয়েছি। অতঃপর, newDish অবজেক্টের মাধ্যমে এর cook নামের স্ট্রং প্রোপার্টিটির ভেতর আমাদের একটু আগে তৈরি করা tomi অবজেক্টটিকে অ্যাসাইন করেছি। এই প্রোগ্রামকে রান করালে কনসোলে আউটপুট আসবে “Tomi Mia is cooking the Halim”।
যেহেতু, cook একটি strong relationship তাই newDish অবজেক্টটি tomi এর ownership নিয়ে নেয় এবং এটা ততক্ষণ পর্যন্ত ভ্যালিড থাকে যতক্ষণ পর্যন্ত tomi কে newDish এর প্রয়োজন হয়।

এখন সবকিছু ঠিক রেখেই শুধুমাত্র main.m কে নিচের মত করে আপডেট করুন,

// main.m

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

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

        Person *tomi = [[Person alloc] init];
        tomi.name = @"Tomi Mia";
        
        Food *newDish = [[Food alloc] init];
        newDish.item = @"Halim";
        newDish.cook = tomi;

        tomi = nil; // Trying to deallocating the "tomi" object

        NSLog(@"%@ is cooking the %@", newDish.cook, newDish.item);
        
    }
    return 0;
}

এখানে আমরা একটা ধাপে tomi অবজেক্টকে ম্যানুয়ালি nil করেছি কিন্তু প্রোগ্রামটি রান করে দেখুন আউটপুট আগের মতই আসবে, “Tomi Mia is cooking the Halim”।

কিন্তু,

এবার নিচের মত করে Food.h ফাইলকে আপডেট করুন,

// Food.h

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

@interface Food : NSObject

@property (nonatomic) NSString *item;
@property (nonatomic, weak) Person *cook;

@end

অর্থাৎ cook কে weak করে ফেলুন এবং main.m রাখুন একটু আগে যেমন ছিল তেমনি,

// main.m

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

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

        Person *tomi = [[Person alloc] init];
        tomi.name = @"Tomi Mia";
        
        Food *newDish = [[Food alloc] init];
        newDish.item = @"Halim";
        newDish.cook = tomi;

        tomi = nil; // Trying to deallocating the "tomi" object

        NSLog(@"%@ is cooking the %@", newDish.cook, newDish.item);
        
    }
    return 0;
}

এবার প্রোগ্রামটিকে রান করালে আউটপুট আসবে “(null) is cooking the Halim”। অর্থাৎ tomi অবজেক্ট ডিঅ্যালোকেট হবার পর newDish এর weak প্রোপার্টি cook, tomi কে হারিয়ে ফেলছে। কিন্তু ১৮ নাম্বার লাইনটি মুছে ফেলে দেখুন, কনসোলে আগের মত আউটপুট আসবে।

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

কপি (copy) অ্যাট্রিবিউটঃ
এটি মোটামুটি strong এর মতই কিন্তু বিশাল একটা পার্থক্য আছে। স্ট্রং এর মত সরাসরি অবজেক্টের ownership না নেয়ার বদলে এটি প্রথমে, ওই প্রোপার্টির মধ্যে যা অ্যাসাইন করা হয় সেটার একটা কপি তৈরি করে এবং সেই কপিটির ownership নিয়ে রাখে। যে ধরনের প্রোপার্টি গুলো ভ্যালু রিপ্রেজেন্ট করে সেগুলোই সাধারণত copy হিসেবে ডিক্লেয়ার করা হয় যেমন NSString টাইপের প্রোপার্টি গুলো।

@property (nonatomic, copy) NSString *item;

আরও যেসব অ্যাট্রিবিউট রয়েছেঃ

  • retain
  • unsafe_unretained
  • assign

পরের চ্যাপ্টারঃ
পরের চ্যাপ্টারে থাকছে মেথড নিয়ে বিস্তারিত আলোচনা। এদের নেমিং কনভেনশন, ডাইনামিক মেথড কলিং ইত্যাদি।

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