body প্রপার্টি SwiftUI-তে View প্রোটোকলের কেন্দ্রীয় উপাদান, যা নির্ধারণ করে স্ক্রিনে কী কন্টেন্ট প্রদর্শিত হবে। Apple Developer Documentation, 2024 অনুসারে, body View প্রোটোকলের একমাত্র বাধ্যতামূলক প্রয়োজনীয়তা এবং এটি এমন একটি টাইপ রিটার্ন করে যা একই প্রোটোকল অনুসরণ করে। SwiftUI প্রতিটি স্টেট পরিবর্তনে body কল করে উপাদানগুলির একটি নতুন ট্রি তৈরি এবং তুলনা করার জন্য।
মূল পয়েন্ট
body একটি কম্পিউটেড প্রপার্টি যা View প্রোটোকলের একমাত্র বাধ্যতামূলক প্রয়োজনীয়তা। View অনুসরণকারী প্রতিটি স্ট্রাকচারকে body বাস্তবায়ন করতে হবে। প্রপার্টিটি সেই কন্টেন্ট রিটার্ন করে যা SwiftUI স্ক্রিনে প্রদর্শন করে — এটি টেক্সট, ইমেজ, বাটন, নেস্টেড উপাদান সহ কন্টেইনার বা View প্রোটোকল অনুসরণকারী অন্য যেকোনো টাইপ হতে পারে।
body-এর সিগনেচার সর্বদা নির্ধারিত: var body: some View { get }। রিটার্ন টাইপ হল some View (একটি অস্বচ্ছ টাইপ), কোনো কংক্রিট টাইপ নয়। এর মানে হল বিভিন্ন Views body-তে বিভিন্ন কংক্রিট টাইপ রিটার্ন করতে পারে, কিন্তু Swift কম্পাইলার প্রতিটি বাস্তবায়নের জন্য কম্পাইল টাইমে কংক্রিট টাইপ নির্ধারণ করে।
WWDC 2022 অনুসারে, body ডিক্লারেটিভ ইন্টারফেস বর্ণনার প্রবেশ বিন্দু। UIKit-এর বিপরীতে, যেখানে আপনি ইম্পেরেটিভভাবে UIView তৈরি এবং কনফিগার করেন, SwiftUI-তে আপনি ডিক্লারেটিভভাবে বর্ণনা করেন কী প্রদর্শিত হবে, এবং SwiftUI নিজেই হিসাব করে কীভাবে এটি বাস্তবায়ন করতে হবে।
body-কে পিওর ফাংশনের মতো আচরণ করা উচিত — একই ইনপুট (স্ট্রাকচার প্রপার্টি এবং স্টেট) সহ এটি একই View ট্রি রিটার্ন করবে। যদি body বাহ্যিক পরিবর্তনশীল স্টেট (গ্লোবাল ভেরিয়েবল, @AppStorage র্যাপার ছাড়া UserDefaults) এর উপর নির্ভর করে, আচরণ অপ্রত্যাশিত হয়ে যায় এবং SwiftUI ভুলভাবে স্ক্রিন পুনরায় আঁকতে পারে।
কম্পিউটেড প্রপার্টি body কোনো মান সংরক্ষণ করে না — এটি প্রতিবার অ্যাক্সেস করার সময় গণনা করা হয়। যখন SwiftUI নির্ধারণ করে যে স্টেট পরিবর্তিত হয়েছে, এটি View স্ট্রাকচার পুনরায় তৈরি করে এবং প্রদর্শনের জন্য বর্তমান উপাদান ট্রি পেতে body-এর নতুন মান পড়ে।
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack {
Text("কাউন্টার: \(count)")
.font(.largeTitle)
Button("বৃদ্ধি") {
count += 1
}
.padding()
.background(.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
}
}
এই উদাহরণে, body একটি VStack রিটার্ন করে যাতে একটি টেক্সট এবং মডিফায়ার সহ একটি বাটন রয়েছে। বাটন চাপলে, @State প্রপার্টি count বৃদ্ধি পায়, SwiftUI CounterView স্ট্রাকচার পুনরায় তৈরি করে এবং নতুন টেক্সট মান সহ আপডেটেড ট্রি পেতে body-কে আবার কল করে।
মডিফায়ার (.font, .padding, .background, .foregroundColor, .cornerRadius) মূল View-কে পরিবর্তন করে না বরং এটিকে ModifiedContent-এ মোড়ায় — একটি নতুন টাইপ যা পরিবর্তন যোগ করে। প্রতিটি মডিফায়ার নেস্টিংয়ের আরেকটি স্তর তৈরি করে, যা পারফরম্যান্সের জন্য বিবেচনা করা গুরুত্বপূর্ণ।
some View body-এর রিটার্ন টাইপে শুধু একটি সম্মেলন নয় বরং কম্পাইলারের প্রয়োজনীয়তা। Swift প্রয়োজন করে যে body-তে সমস্ত রিটার্ন পাথের একই কংক্রিট টাইপ থাকতে হবে। @ViewBuilder ছাড়া আপনি একটি শাখায় Text এবং অন্যটিতে Button রিটার্ন করতে পারবেন না — কম্পাইলার ত্রুটি দেবে।
struct ConditionalView: View {
var isReady: Bool
@ViewBuilder
var body: some View {
if isReady {
Text("প্রস্তুত")
.foregroundColor(.green)
} else {
ProgressView()
}
}
}
body-তে @ViewBuilder কম্পাইলার ত্রুটি ছাড়াই শর্তসাপেক্ষ লজিক (if/else, switch) ব্যবহার করতে দেয়। ViewBuilder স্বয়ংক্রিয়ভাবে বিভিন্ন শাখাকে ConditionalContent-এ মোড়ায় — একটি বিশেষ টাইপ যা কংক্রিট টাইপ পার্থক্য লুকায়। গতিশীল ইন্টারফেস তৈরির জন্য এটি একটি মূল ক্ষমতা।
@ViewBuilder ছাড়া কম্পাইলার সমস্ত রিটার্ন পাথের জন্য একটি একক টাইপ অনুমান করার চেষ্টা করে। যদি টাইপ ভিন্ন হয় — ত্রুটি ঘটে। এই কারণেই SwiftUI View ডিক্লারেশনে body-তে অন্তর্নিহিতভাবে @ViewBuilder প্রয়োগ করে, যদিও ইউজার কোডে আপনাকে কাস্টম মেথড এবং প্রপার্টির জন্য স্পষ্টভাবে অ্যানোটেশন যোগ করতে হবে যা একাধিক Views রিটার্ন করে।
কংক্রিট টাইপের পরিবর্তে some View ব্যবহার করলে পারফরম্যান্স কমে না — কম্পাইলার কম্পাইল টাইমে সঠিক টাইপ জানে এবং ডায়নামিক ডিসপ্যাচ ছাড়াই সরাসরি কোড জেনারেট করে। AnyView, বিপরীতে, একটি অস্তিত্বগত কন্টেইনারে মোড়ানোর ওভারহেড সহ টাইপ ইরেজার ব্যবহার করে।
body SwiftUI দ্বারা তিনটি প্রধান পরিস্থিতিতে কল হয়: যখন View প্রথমবার প্রদর্শিত হয়, যখন @State/@Binding/@ObservedObject/@StateObject পরিবর্তিত হয়, এবং যখন প্যারেন্ট View ইনিশিয়ালাইজারের মাধ্যমে নতুন মান পাস করে। SwiftUI এনভায়রনমেন্ট ভ্যালু (@Environment) পরিবর্তিত হলেও body কল করতে পারে।
body কলের ফ্রিকোয়েন্সি আপনাকে চিন্তিত করা উচিত নয় — SwiftUI আইডেন্টিটি মেকানিজমের মাধ্যমে পুনরায় আঁকা অপ্টিমাইজ করে। অনুক্রমের প্রতিটি View-এর একটি অনন্য আইডেন্টিফায়ার আছে। যদি আইডেন্টিটি এবং ইনপুট ডেটা পরিবর্তিত না হয় — body কল হয় না এমনকি প্যারেন্ট View পুনরায় আঁকালেও। এটি Equatable তুলনা এবং কাঠামোগত স্থিতিশীলতার মাধ্যমে অর্জিত হয়।
struct ParentView: View {
var body: some View {
ChildView(name: "Alice") // স্থিতিশীল আইডেন্টিটি
}
}
struct ChildView: View {
let name: String
var body: some View {
Text("হ্যালো, \(name)!")
}
}
এই উদাহরণে, যদি ParentView পুনরায় আঁকে কিন্তু একই name মান পাস করে — ChildView.body কল হয় না। SwiftUI স্ট্রাকচারের ইনপুট ডেটা তুলনা করে এবং, যদি অপরিবর্তিত থাকে, চাইল্ড কম্পোনেন্টের পুনরায় আঁকা এড়িয়ে যায়। এটি ভিউ ডিফারেন্সিয়েশন মেকানিজম।
কয়েকটি সমস্যা body-এর অপ্রত্যাশিত কলের কারণ হয়: ObservableObject ছাড়া ক্লাস ব্যবহার, body-এর ভিতরে তৈরি ক্লোজার পাস করা (প্রতিটি ক্লোজার তৈরি একটি নতুন আইডেন্টিটি দেয়), এবং EquatableView-এর ভুল ব্যবহার। যদি body খুব বেশি বার কল হয় — সমস্ত চাইল্ড কম্পোনেন্টের আইডেন্টিটি স্থিতিশীলতা পরীক্ষা করুন।
প্রথম নিয়ম: body ন্যূনতম হওয়া উচিত। জটিল লজিক পৃথক কম্পিউটেড প্রপার্টি বা মেথডে স্থানান্তর করুন যা View রিটার্ন করে। এটি পড়ার যোগ্যতা উন্নত করে এবং SwiftUI-কে আরও নির্ভুলভাবে নির্ধারণ করতে দেয় অনুক্রমের কোন অংশগুলি পরিবর্তিত হয়েছে। বড় bodies-কে স্পষ্ট দায়িত্ব সীমা সহ উপ-কম্পোনেন্টে ভাগ করুন।
দ্বিতীয় নিয়ম: কাজ সম্পাদনের জন্য body ব্যবহার করবেন না। ডেটা লোডিং, নেটওয়ার্ক অপারেশন, ডাটাবেস রাইটিং — এই সব body-র বাইরে, টাস্ক, onChange মডিফায়ার বা ObservableObject-এর মাধ্যমে হওয়া উচিত। body শুধুমাত্র ইন্টারফেস ডিক্লারেশনের জন্য উদ্দেশ্য।
তৃতীয় নিয়ম: View-এর জন্য EquatableView প্রপার্টি বা কাস্টম Equatable প্রোটোকল ব্যবহার করুন যদি স্ট্যান্ডার্ড কাঠামোগত তুলনা অপর্যাপ্ত হয়। এটি SwiftUI-কে স্পষ্টভাবে জানাতে দেয় কখন একটি চাইল্ড View-এর পুনরায় আঁকার প্রয়োজন এবং অপ্রয়োজনীয় body কল এড়ায়।
চতুর্থ নিয়ম: যদি body-তে জটিল গণনা (ফরম্যাটিং, ফিল্টারিং, সর্টিং) থাকে — ফলাফল ক্যাশ করতে @State ব্যবহার করুন বা গণনাগুলি onChange থেকে কল করা পৃথক মেথডে স্থানান্তর করুন। প্রতিটি স্টেট আপডেটের সাথে body-তে পুনরাবৃত্ত গণনা অ্যানিমেশন মন্থরতার একটি সাধারণ কারণ।
পঞ্চম নিয়ম: তালিকার জন্য (List, ForEach) id প্যারামিটারের মাধ্যমে স্থির আইডেন্টিফায়ার নিশ্চিত করুন। স্থির আইডেন্টিটি ছাড়া, ForEach যেকোনো পরিবর্তনে সমস্ত উপাদান পুনরায় তৈরি করে, প্রতিটির জন্য body কল করে, এমনকি যদি শুধুমাত্র একটি উপাদান পরিবর্তিত হয়।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
body View প্রোটোকলের কম্পিউটেড প্রপার্টি যা প্রদর্শনের জন্য কন্টেন্ট রিটার্ন করে। এটি প্রোটোকলের একমাত্র বাধ্যতামূলক প্রয়োজনীয়তা। রিটার্ন টাইপ some View, যা SwiftUI-কে কম্পাইল টাইমে অনুক্রম অপ্টিমাইজ করতে দেয়।
হ্যাঁ, SwiftUI প্রতিটি স্টেট পরিবর্তনে (@State, @Binding, @ObservedObject) বা ইনপুট ডেটা পরিবর্তনে body কল করে। এটি একটি ডিক্লারেটিভ ফ্রেমওয়ার্কের জন্য স্বাভাবিক আচরণ। SwiftUI আইডেন্টিটি মেকানিজম এবং Equatable তুলনার মাধ্যমে কল ফ্রিকোয়েন্সি অপ্টিমাইজ করে।
some View একটি অস্বচ্ছ টাইপ যা কংক্রিট বাস্তবায়ন লুকায়। কম্পাইলার কম্পাইল টাইমে টাইপ নির্ধারণ করে, সরাসরি কল পারফরম্যান্স নিশ্চিত করে। এটি নমনীয়তা প্রদান করে: আপনি সিগনেচার পরিবর্তন না করেই রিটার্ন টাইপ পরিবর্তন করতে পারেন।
না, body অপশনাল হতে পারে না — রিটার্ন টাইপ some View nil অনুমতি দেয় না। যদি শর্তসাপেক্ষে কোনো উপাদান লুকানোর প্রয়োজন হয়, @ViewBuilder-এর ভিতরে শর্তসাপেক্ষ লজিক ব্যবহার করুন বা EmptyView রিটার্ন করুন, যা অনুক্রমে কোনো স্থান নেয় না।
প্রতিটি মডিফায়ার একটি নতুন ModifiedContent স্তর তৈরি করে, অনুক্রমের গভীরতা বাড়ায়। অধিকাংশ স্ক্রিনের জন্য (৫০টি মডিফায়ার পর্যন্ত) প্রভাব নগণ্য। অত্যধিক মডিফায়ার সংখ্যা (শত) ডিফিং ধীর করতে পারে। সম্পর্কিত মডিফায়ারগুলিকে কাস্টম এক্সটেনশনে গ্রুপ করুন।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন