some View হল একটি মূল Swift সিনট্যাকটিক্যাল কনস্ট্রাক্ট যা ছাড়া SwiftUI কাজ করতে পারে না। Apple Swift Book, 2024 অনুসারে, some View হল একটি অস্বচ্ছ টাইপ (opaque type) যা নির্দিষ্ট রিটার্ন টাইপ লুকিয়ে রাখে, কম্পাইল টাইমে কঠোর টাইপিং বজায় রেখে। এই কনস্ট্রাক্ট View প্রোটোকলকে বাস্তবায়নের বিবরণ প্রকাশ না করেই একটি ইউনিফায়েড body সিগনেচার রাখার অনুমতি দেয়।
মূল পয়েন্ট
some View হল Swift 5.1-এ প্রবর্তিত একটি অস্বচ্ছ টাইপ সিনট্যাক্স। এটি View প্রোটোকলের body প্রপার্টির রিটার্ন টাইপ হিসেবে ব্যবহৃত হয়। some View নোটেশনটির অর্থ: "ফাংশন বা প্রপার্টি কিছু কংক্রিট টাইপ রিটার্ন করে যা View প্রোটোকল মেনে চলে, কিন্তু কলিং কোড জানে না এবং জানার প্রয়োজন নেই যে আসলে কোন টাইপটি"।
অস্বচ্ছ টাইপ ধারণাটি জেনেরিক প্রোগ্রামিং (generics)-এর বিপরীত দিক। যদি generics কলিং কোডকে টাইপ নির্ধারণের অনুমতি দেয়, তাহলে অস্বচ্ছ টাইপ বাস্তবায়নকে টাইপ নির্ধারণের অনুমতি দেয়, এটি কলকারীর থেকে লুকিয়ে রাখে। এটি ডেভেলপারকে চুক্তি পরিবর্তন না করেই অভ্যন্তরীণ বাস্তবায়ন পরিবর্তনের স্বাধীনতা দেয়।
Swift Evolution SE-0244 অনুসারে, অস্বচ্ছ টাইপগুলি SwiftUI এবং অ্যাসোসিয়েটেড টাইপ (PAT) সহ প্রোটোকল প্যাটার্ন সমর্থন করার জন্য যুক্ত করা হয়েছিল, যা এই কনস্ট্রাক্ট ছাড়া রিটার্ন টাইপ হিসাবে ব্যবহার করা যায় না।
some View ছাড়া, body সিগনেচার অসম্ভব হবে: View প্রোটোকলের একটি অ্যাসোসিয়েটেড টাইপ Body আছে যা View মেনে চলে। যদি body কেবল View (প্রোটোকল হিসাবে) রিটার্ন করত, তাহলে Swift রিটার্ন পজিশনে Self প্রয়োজনীয়তা সহ প্রোটোকল নিয়ে কাজ করতে পারত না। some View একটি কংক্রিট কিন্তু লুকানো টাইপ প্রদান করে এই সমস্যার সমাধান করে।
অস্বচ্ছ টাইপ হল একটি বিশেষ ধরনের টাইপ যা কম্পাইলারের জন্য কংক্রিট কিন্তু ডেভেলপারের জন্য অ্যাবস্ট্রাক্ট আচরণ করে। যখন কম্পাইলার some View দেখে, এটি বাস্তবায়ন বিশ্লেষণ করে এবং সঠিক রিটার্ন টাইপ নির্ধারণ করে। এই টাইপটি স্থির করা হয় এবং ডায়নামিক ডিসপ্যাচ ছাড়াই কোড জেনারেশনের জন্য ব্যবহৃত হয়।
struct SimpleView: View {
var body: some View {
Text("হ্যালো")
}
}
// কম্পাইলার দেখে: body -> Text, not some View
কাজ করার নীতি: Swift কম্পাইলার বাস্তবায়ন থেকে কংক্রিট টাইপ অনুমান করে। উপরের উদাহরণে, body-তে শুধু Text আছে, তাই কম্পাইলার জানে যে body আসলে Text রিটার্ন করে, যদিও সিগনেচার some View হিসেবে লেখা হয়েছে। এটি দুটি অপ্টিমাইজেশন প্রদান করে: ভার্চুয়াল মেথড টেবিল ছাড়া সরাসরি কল এবং ইনলাইনিংয়ের সম্ভাবনা।
যদি body-র বাস্তবায়ন পরিবর্তিত হয় (উদাহরণস্বরূপ, Text-এর পরিবর্তে Text এবং Button-এর VStack রিটার্ন করা হয়), কম্পাইলার কংক্রিট টাইপ পুনরায় নির্ধারণ করে। কিন্তু কলিং কোডের (SwiftUI) জন্য, সিগনেচার একই থাকে — some View। এটি generics-এর বিপরীত দিক: কলিং কোড বাস্তবায়ন পরিবর্তনের উপর নির্ভর করে না।
অস্বচ্ছ টাইপের একটি মূল নিয়ম: some View রিটার্নকারী ফাংশন বা প্রপার্টিকে সর্বদা একই কংক্রিট টাইপ রিটার্ন করতে হবে। আপনি একটি if শাখায় Text এবং অন্যটিতে Image রিটার্ন করতে পারবেন না। এই সীমাবদ্ধতা কম্পাইলার দ্বারা পরীক্ষা করা হয় এবং কলিং কোডের জন্য গ্যারান্টি হিসেবে কাজ করে।
struct BadView: View {
var flag: Bool
var body: some View {
if flag {
Text("সত্য") // ত্রুটি: Text vs VStack
} else {
VStack {
Text("মিথ্যা")
Image(systemName: "xmark")
}
}
}
}
এই সমস্যা সমাধানের জন্য @ViewBuilder ব্যবহার করা হয়, যা বিভিন্ন শাখাকে ConditionalContent কন্টেইনারে মোড়ানো করে। body-তে @ViewBuilder অ্যানোটেশন SwiftUI-তে মানক অভ্যাস, যদিও body-তে যদি কেবল একটি এক্সপ্রেশন থাকে তবে এটি অন্তর্নিহিত হতে পারে।
AnyView হল একটি টাইপ যা View-এর কংক্রিট বাস্তবায়ন মুছে ফেলে (type erasure)। এটি যেকোনো View-কে একটি একক আবরণে মোড়ানো করে, বিভিন্ন টাইপের View-কে একই কন্টেইনারে সংরক্ষণের অনুমতি দেয়। some View-এর বিপরীতে, AnyView রানটাইমে কাজ করে এবং মোড়ানো ও খোলার অতিরিক্ত ওভারহেড যোগ করে।
| মাপকাঠি | some View | AnyView |
|---|---|---|
| সমাধানের সময় | কম্পাইল টাইম | রানটাইম |
| কর্মক্ষমতা | সরাসরি কল, ওভারহেড নেই | existential container-এ মোড়ানো |
| টাইপ নমনীয়তা | একটি কংক্রিট টাইপ | যেকোনো View টাইপ |
| গতিশীল পরিবর্তন | সমর্থিত নয় | রানটাইমে সমর্থিত |
| ব্যবহারের অগ্রাধিকার | যখনই সম্ভব | শুধুমাত্র যখন some View অসম্ভব |
| PAT প্রোটোকল সমর্থন | হ্যাঁ | হ্যাঁ |
কখন AnyView ব্যবহার করবেন: শুধুমাত্র সেই পরিস্থিতিতে যেখানে রানটাইমে গতিশীল টাইপ পরিবর্তনের প্রয়োজনীয়তার কারণে some View অসম্ভব। উদাহরণস্বরূপ, ডিকশনারি থেকে View রিটার্ন করার সময় বা পুনরাবৃত্তিমূলক কাঠামোতে যেখানে প্রতিটি স্তরে কংক্রিট টাইপ পরিবর্তন করতে হবে। AnyView ন্যূনতম করা উচিত, কারণ প্রতিটি মোড়ানো SwiftUI অপ্টিমাইজেশন নিষ্ক্রিয় করে।
সাধারণ ভুল ধারণা: AnyView body-তে বিভিন্ন টাইপের সমস্যা সমাধান করে না — @ViewBuilder এটি সমাধান করে। AnyView টাইপ মুছে ফেলে কিন্তু কম্পাইলারকে একক টাইপ অনুমান করতে সাহায্য করে না। শর্তসাপেক্ষ লজিকের জন্য @ViewBuilder এবং শুধুমাত্র গতিশীল ডিসপ্যাচের জন্য AnyView ব্যবহার করুন।
@ViewBuilder হল একটি result builder যা বিশেষভাবে some View-এর সাথে কাজ করার জন্য ডিজাইন করা হয়েছে। এটি body-তে শর্তসাপেক্ষ লজিক (if/else, switch) এবং একাধিক এক্সপ্রেশন ব্যবহারের অনুমতি দেয়, একক রিটার্ন টাইপ বজায় রেখে। ViewBuilder স্বয়ংক্রিয়ভাবে একাধিক এক্সপ্রেশনকে TupleView-এ এবং শর্তসাপেক্ষ শাখাগুলোকে ConditionalContent-এ মোড়ানো করে।
struct ProfileView: View {
let user: User?
@ViewBuilder
var body: some View {
if let user {
UserCard(user: user)
Text("অনলাইন")
.font(.caption)
} else {
ProgressView("Loading...")
}
}
}
এটি কীভাবে কাজ করে: @ViewBuilder কোড ব্লক বিশ্লেষণ করে এবং উপযুক্ত buildBlock, buildOptional বা buildEither কল জেনারেট করে। শর্তসাপেক্ষ লজিকের জন্য ConditionalContent তৈরি করা হয় — একটি সাধারণ টাইপ যা শাখার ভিতরের কংক্রিট টাইপগুলো লুকিয়ে রাখে কিন্তু নিজে কম্পাইলারের জন্য একটি একক টাইপ। এটি বিভিন্ন কংক্রিট টাইপের সমস্যা সমাধান করে।
@ViewBuilder ছাড়া, body প্রপার্টি যাতে একাধিক এক্সপ্রেশন বা শর্তসাপেক্ষ লজিক থাকে তা কম্পাইলেশন ত্রুটির কারণ হবে। এই কারণেই SwiftUI body-তে @ViewBuilder অন্তর্নিহিতভাবে প্রয়োগ করে, এবং কাস্টম প্রপার্টি এবং ফাংশনের জন্য এটি স্পষ্টভাবে যোগ করতে হবে।
@ViewBuilder নেস্টেড হতে পারে: একটি ViewBuilder অন্যটির ভিতরে। এটি বিভিন্ন স্তরে শর্ত সহ জটিল শ্রেণিবিন্যাস তৈরি করার অনুমতি দেয়। তবে, গভীর নেস্টিং পঠনযোগ্যতা জটিল করে তোলে, তাই নেস্টেড শর্তগুলোকে আলাদা View কম্পোনেন্টে বের করে আনার পরামর্শ দেওয়া হয়।
উদাহরণ 1: গণনাকৃত প্রপার্টি থেকে কাস্টম View রিটার্ন করা। একটি প্রপার্টি some View রিটার্ন করতে পারে, অভ্যন্তরীণ কম্পোজিশন লুকিয়ে রেখে। এটি পাবলিক ইন্টারফেস পরিবর্তন না করেই কোড পুনর্গঠনের অনুমতি দেয়।
struct ArticleView: View {
var body: some View {
CardView {
HeaderView()
ContentView()
FooterView()
}
}
}
struct CardView<Content: View>: View {
let content: Content
var body: some View {
content
.padding(16)
.background(.white)
.cornerRadius(12)
.shadow(radius: 4)
}
}
উদাহরণ 2: @ViewBuilder-এর মাধ্যমে View-কে ক্লোজার হিসেবে পাস করা। এই প্যাটার্নটি স্ট্যান্ডার্ড SwiftUI কন্টেইনার (VStack, HStack, List) এ ব্যবহৃত হয় এবং কাস্টম কম্পোনেন্টে বাস্তবায়ন করা যেতে পারে।
struct CustomContainer<Content: View>: View {
@ViewBuilder let content: () -> Content
var body: some View {
VStack(alignment: .leading) {
content()
}
.padding(20)
}
}
উদাহরণ 3: একটি ফ্যাক্টরি ফাংশন যা some View রিটার্ন করে। বাস্তবায়ন প্রকাশ না করেই প্যারামিটারের উপর ভিত্তি করে View তৈরি করার অনুমতি দেয়। এটি লাইব্রেরি এবং পুনর্ব্যবহারযোগ্য কম্পোনেন্টের জন্য বিশেষভাবে উপযোগী।
func makeIcon(for status: Status) -> some View {
switch status {
case .success:
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)
case .error:
Image(systemName: "xmark.circle.fill")
.foregroundColor(.red)
case .pending:
ProgressView()
}
}
সচরাচর জিজ্ঞাসিত প্রশ্ন
some View হল একটি অস্বচ্ছ টাইপ, যার অর্থ হল View প্রোটোকল মেনে চলা কিছু কংক্রিট টাইপ রিটার্ন করা হয়। কংক্রিট টাইপ কম্পাইলার দ্বারা নির্ধারিত কিন্তু কলিং কোড থেকে লুকানো। এটি বাস্তবায়নের বিবরণ প্রকাশ না করেই কঠোর টাইপিং নিশ্চিত করে।
some View শূন্য ওভারহেড সহ কম্পাইল টাইমে সমাধান করা হয়। AnyView রানটাইমে existential container-এ মোড়ানোর অতিরিক্ত খরচ সহ type erasure ব্যবহার করে। যখনই সম্ভব some View ব্যবহার করুন, AnyView শুধুমাত্র গতিশীল টাইপ পরিবর্তনের জন্য।
অস্বচ্ছ টাইপের জন্য সব রিটার্ন পাথের একক কংক্রিট টাইপ প্রয়োজন। বিভিন্ন টাইপের সাথে if/else এই প্রয়োজনীয়তা লঙ্ঘন করে। @ViewBuilder শাখাগুলোকে ConditionalContent — একটি একক টাইপ যা কংক্রিট বাস্তবায়নের পার্থক্য লুকিয়ে রাখে — এ মোড়িয়ে সমস্যার সমাধান করে।
some View কর্মক্ষমতা হ্রাস করে না — কম্পাইলার সঠিক টাইপ জানে এবং সরাসরি কোড জেনারেট করে। বিপরীতে, any View (প্রোটোকল হিসাবে) গতিশীল ডিসপ্যাচের প্রয়োজন হবে। some View হল SwiftUI-এর ডিজাইনে নির্মিত একটি অপ্টিমাইজেশন মেকানিজম।
হ্যাঁ, some হল Swift 5.1-এর একটি সাধারণ কনস্ট্রাক্ট যা SwiftUI-এর সাথে আবদ্ধ নয়। এটি যেকোনো প্রোটোকলের সাথে ব্যবহার করা যেতে পারে: some Equatable, some Codable, some Collection। এটি [String: [Int]]-এর মতো জটিল নেস্টেড টাইপ লুকানোর জন্য উপযোগী।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন