setNeedsDisplay() UIView-এর একটি ইনস্ট্যান্স মেথড যা ভিউকে পুনরায় অঙ্কনের প্রয়োজন হিসাবে চিহ্নিত করে। সরাসরি draw(_:) কল করার বিপরীতে, setNeedsDisplay() শুধুমাত্র ভিউ-এর জন্য dirty ফ্ল্যাগ সেট করে এবং অবিলম্বে নিয়ন্ত্রণ ফেরত দেয়। সিস্টেম এই অনুরোধটি নিকটতম রেন্ডারিং চক্রে প্রক্রিয়া করে, যা একাধিক কলকে একটি ড্র অপারেশনে একত্রিত করতে দেয়। Apple ডকুমেন্টেশন (2025) অনুসারে, setNeedsDisplay()-এর মাধ্যমে বিলম্বিত পুনরায় অঙ্কনই কাস্টম UIView-এর বিষয়বস্তু আপডেট করার একমাত্র সঠিক উপায়।
মূল বিষয়
setNeedsDisplay() একটি UIView মেথড যা সিস্টেমকে সংকেত দেয় যে ভিউ-এর বিষয়বস্তু পুরানো হয়ে গেছে এবং পুনরায় রেন্ডার করার প্রয়োজন। মেথডটি কোনো প্যারামিটার নেয় না এবং void রিটার্ন করে। কল করার পরে, ভিউটি dirty হিসাবে চিহ্নিত হয়, এবং নিকটতম ড্র চক্রে সিস্টেম এই ভিউ-এর জন্য draw(_:) কল করে।
মূল বৈশিষ্ট্য হল অ্যাসিঙ্ক্রোনাসিটি। একই ভিউ-এর জন্য ধারাবাহিকভাবে একাধিক setNeedsDisplay() কল draw(_:) এর একাধিক কলের ফলে হবে না — সিস্টেম সেগুলিকে একটি অপারেশনে একত্রিত করে। এটি পারফরম্যান্সের জন্য অত্যন্ত গুরুত্বপূর্ণ: যদি কোনো ভিউ প্রপার্টি প্রতি ফ্রেমে একাধিকবার পরিবর্তিত হয়, তবে draw(_:) শুধুমাত্র একবার কল হয়।
বিলম্বিত পুনরায় অঙ্কন প্রক্রিয়াটি UIKit রেন্ডারিং চক্রের উপর ভিত্তি করে। যখন setNeedsDisplay() কল করা হয়, সিস্টেম অভ্যন্তরীণ ফ্ল্যাগ layer.needsDisplay true-তে সেট করে। বর্তমান run loop-এর শেষে, সিস্টেম সমস্ত dirty লেয়ারের মধ্য দিয়ে যায় এবং প্রতিটির জন্য draw(_:) কল করে।
UIKit run loop-এ একটি আপডেট পর্যায় অন্তর্ভুক্ত রয়েছে যার সময় dirty ভিউ প্রক্রিয়া করা হয়। এই পর্যায়ে, প্রয়োজন হলে layoutSubviews() কল করা হয়, তারপর সমস্ত চিহ্নিত ভিউ-এর জন্য draw(_:) কল করা হয়। অঙ্কন সম্পূর্ণ হওয়ার পরে, ফলাফল কম্পোজিটিং-এর জন্য Core Animation-এর মাধ্যমে GPU-তে পাঠানো হয়।
class ProgressView: UIView {
var progress: CGFloat = 0 {
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let ctx = UIGraphicsGetCurrentContext() else { return }
// পৃষ্ঠভূমি
ctx.setFillColor(UIColor.lightGray.cgColor)
ctx.fill(rect)
// অগ্রগতি বার
let fillRect = CGRect(x: rect.minX, y: rect.minY,
width: rect.width * progress, height: rect.height)
ctx.setFillColor(UIColor.systemGreen.cgColor)
ctx.fill(fillRect)
}
}
এই উদাহরণে, progressView progress আপডেট করে, এবং প্রতিটি সেটার স্বয়ংক্রিয়ভাবে setNeedsDisplay() কল করে। সিস্টেম run loop-এর শেষ পর্যন্ত অপেক্ষা করে এবং প্রকৃত progress মান সহ draw(_:) কল করে। যদি progress প্রতি ফ্রেমে তিনবার পরিবর্তিত হয়, তবে draw(_:) শুধুমাত্র একবার সম্পাদিত হয় — শেষ মান দিয়ে।
setNeedsDisplay(_:) মেথডটি CGRect টাইপের একটি rect প্যারামিটার নেয়, যা পুনরায় অঙ্কন এলাকা সীমিত করে। এটি সম্পূর্ণ ভিউ-এর পরিবর্তে শুধুমাত্র পরিবর্তিত অংশটি পুনরায় আঁকতে দেয়। পারফরম্যান্সের পার্থক্য বড় ভিউ-এর সাথে কাজ করার সময় লক্ষণীয় হয় যেখানে পরিবর্তনগুলি ছোট এলাকাকে প্রভাবিত করে।
| বৈশিষ্ট্য | setNeedsDisplay() | setNeedsDisplay(_:) |
|---|---|---|
| প্যারামিটার | কোনোটি নয় | CGRect — পুনরায় অঙ্কন এলাকা |
| পুনরায় অঙ্কন এলাকা | সম্পূর্ণ ভিউ bounds | শুধুমাত্র নির্দিষ্ট আয়তক্ষেত্র |
| পারফরম্যান্স | বড় ভিউ-এর জন্য কম | আংশিক পরিবর্তনের জন্য বেশি |
| draw(_:) এ rect প্যারামিটার | সম্পূর্ণ bounds | নির্দিষ্ট আয়তক্ষেত্র |
| কখন ব্যবহার করবেন | সম্পূর্ণ বিষয়বস্তু পরিবর্তন | বিন্দুগত পরিবর্তন (কার্সার, হাইলাইট) |
জটিল গ্রাফিক্সের জন্য, প্রথমে পুরো দৃশ্যটি অফস্ক্রিন কনটেক্সটে আঁকার পরামর্শ দেওয়া হয়, তারপর শুধুমাত্র পরিবর্তিত এলাকার জন্য setNeedsDisplay(_:) কল করুন। এটি iOS-এ ড্রইং অ্যাপ্লিকেশন এবং গ্রাফিক এডিটরগুলিতে একটি মানক কৌশল।
displayIfNeeded() একটি সিঙ্ক্রোনাস মেথড যা run loop-এর শেষের জন্য অপেক্ষা না করেই অনুক্রমের সমস্ত dirty ভিউ-এর পুনরায় অঙ্কন অবিলম্বে শুরু করে। setNeedsDisplay()-এর বিপরীতে, যা শুধুমাত্র একটি ফ্ল্যাগ সেট করে, displayIfNeeded() draw(_:) এর তাৎক্ষণিক সম্পাদন বাধ্য করে।
Apple শুধুমাত্র চরম ক্ষেত্রে displayIfNeeded() ব্যবহার করার পরামর্শ দেয় যখন অঙ্কনের ফলাফল অবিলম্বে প্রয়োজন — উদাহরণস্বরূপ, স্ক্রিনশট নেওয়ার আগে বা UIGraphicsImageRenderer-এর জন্য সিঙ্ক্রোনাস ইমেজ জেনারেশনের সময়। সাধারণ পরিস্থিতিতে, setNeedsDisplay()-এর মাধ্যমে অ্যাসিঙ্ক্রোনাস মডেল পছন্দনীয় কারণ এটি মূল থ্রেডকে ব্লক করে না।
// অ্যাসিঙ্ক্রোনাস — সুপারিশ
someView.setNeedsDisplay()
// সিঙ্ক্রোনাস — শুধুমাত্র প্রয়োজন হলে
someView.setNeedsDisplay()
someView.displayIfNeeded() // draw(_:) তাত্ক্ষণিক ডাকা হয়েছে
পূর্ববর্তী setNeedsDisplay() ছাড়া displayIfNeeded() কল করার কোনো প্রভাব থাকবে না — মেথডটি শুধুমাত্র ইতিমধ্যে dirty হিসাবে চিহ্নিত ভিউ প্রক্রিয়া করে। যদি কোনো ভিউ-এর পুনরায় অঙ্কনের প্রয়োজন না হয়, তবে displayIfNeeded() draw(_:) কল না করেই সম্পূর্ণ হয়।
ঘন ঘন setNeedsDisplay() কল পারফরম্যান্স হ্রাস করতে পারে, বিশেষ করে অ্যানিমেশনের সময়। আসুন প্রধান অপ্টিমাইজেশন কৌশলগুলি দেখি।
পৃথক প্রপার্টির প্রতিটি পরিবর্তনে setNeedsDisplay() কল করার পরিবর্তে, পরিবর্তনগুলি জমা করুন এবং সমস্ত আপডেট প্রয়োগ করার পরে একবার মেথডটি কল করুন। উদাহরণস্বরূপ, একটি উপাদানের রং, আকার এবং অবস্থান পরিবর্তন করার সময় — সমস্ত প্রপার্টি সেট করার পরে একবার setNeedsDisplay() কল করুন।
যদি কোনো প্রপার্টি CALayer-এর মাধ্যমে অ্যানিমেটেড করা যায় (backgroundColor, opacity, position, transform), তাহলে draw(_:) এর পরিবর্তে Core Animation ব্যবহার করুন। CALayer প্রপার্টিগুলি draw(_:) কল না করেই GPU-তে আপডেট হয়, যা CPU লোড ছাড়াই 60 FPS প্রদান করে।
একাধিক পরিবর্তনকে এক রেন্ডারিং পাসে গ্রুপ করতে CATransaction ব্যবহার করুন। এটি লেনদেনের শেষে একাধিক setNeedsDisplay() কলকে একটি draw(_:) অপারেশনে একত্রিত করতে দেয়।
CATransaction.begin()
CATransaction.setDisableActions(true)
view1.setNeedsDisplay()
view2.setNeedsDisplay()
view3.setNeedsDisplay()
CATransaction.commit()
displayIfNeeded() অতিরিক্ত ব্যবহার করবেন না — সিঙ্ক্রোনাস পুনরায় অঙ্কন মূল থ্রেড ব্লক করে এবং ফ্রেম ড্রপের কারণ হতে পারে। এটি শুধুমাত্র সেই অপারেশনগুলির জন্য ব্যবহার করুন যেখানে বর্তমান run loop শেষ হওয়ার আগে অঙ্কনের ফলাফল গুরুত্বপূর্ণ।
সচরাচর জিজ্ঞাসিত প্রশ্ন
না, সরাসরি draw(_:) কল করা নিষিদ্ধ। setNeedsDisplay() ভিউকে dirty হিসাবে সঠিকভাবে চিহ্নিত করে, এবং সিস্টেম রেন্ডারিং চক্রের সঠিক সময়ে draw(_:) কল করে। সরাসরি draw(_:) কল ক্যাশিং মেকানিজমকে উপেক্ষা করে এবং অসামঞ্জস্যপূর্ণ অবস্থার দিকে নিয়ে যেতে পারে।
একই ভিউ-এর জন্য setNeedsDisplay()-এর একাধিক কল সিস্টেম দ্বারা একটি draw(_:) কলে একত্রিত হয়। এটি ঘটে কারণ মেথডটি শুধুমাত্র dirty ফ্ল্যাগ সেট করে, যা run loop-এর শেষে draw(_:) এর প্রকৃত সম্পাদনের পরেই মুছে ফেলা হয়।
setNeedsDisplay() ভিউ-এর বিষয়বস্তুর পুনরায় অঙ্কনের অনুরোধ করে (draw(_:) কল করে)। setNeedsLayout() সাবভিউ-এর পুনর্বিন্যাসের অনুরোধ করে (layoutSubviews() কল করে)। layoutSubviews() আকার পরিবর্তনের কারণ হতে পারে, যা ফলস্বরূপ পুনরায় অঙ্কন ট্রিগার করতে পারে।
setNeedsDisplay(_:) বিন্দুগত পরিবর্তনের জন্য ব্যবহার করা উচিত: কার্সার চলাচল, নির্বাচিত এলাকার রং পরিবর্তন, গ্রাফের অংশ আপডেট করা। এটি পুনরায় অঙ্কন এলাকা সীমিত করে এবং সম্পূর্ণ ভিউ পুনরায় আঁকার তুলনায় পারফরম্যান্স উন্নত করে।
ডিফল্টরূপে, ফ্রেম বা bounds পরিবর্তন setNeedsDisplay() কল করে না। সিস্টেম শুধুমাত্র ভিউ সরিয়ে নেয়। যদি আকার পরিবর্তনের সময় পুনরায় অঙ্কনের প্রয়োজন হয়, তাহলে contentMode প্রপার্টি .redraw-এ সেট করুন — তাহলে UIKit স্বয়ংক্রিয়ভাবে প্রতিটি bounds পরিবর্তনে setNeedsDisplay() কল করবে।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন