जब एक तत्व सक्रिय होता है तो indexpath.row कैसे प्राप्त करें?


104

मेरे पास बटन के साथ एक टेबलव्यू है और मैं इंडेक्सपथ का उपयोग करना चाहता हूं। जब उनमें से एक टैप किया जाता है। यह वही है जो मेरे पास वर्तमान में है, लेकिन यह हमेशा 0 है

var point = Int()
func buttonPressed(sender: AnyObject) {
    let pointInTable: CGPoint =         sender.convertPoint(sender.bounds.origin, toView: self.tableView)
    let cellIndexPath = self.tableView.indexPathForRowAtPoint(pointInTable)
    println(cellIndexPath)
    point = cellIndexPath!.row
    println(point)
}

क्या मुझे पॉइंट वेरिएबल के बजाय IndexPathForSelectedRow () का उपयोग करना चाहिए? या मुझे इसका उपयोग कहां करना चाहिए?
विंसेंट

जवाबों:


166

giorashc लगभग उसके जवाब के साथ था, लेकिन उसने इस तथ्य की अनदेखी की कि सेल की एक अतिरिक्त contentViewपरत है। इस प्रकार, हमें एक परत को गहराई तक जाना है:

guard let cell = sender.superview?.superview as? YourCellClassHere else {
    return // or fatalError() or whatever
}

let indexPath = itemTable.indexPath(for: cell)

ऐसा इसलिए है क्योंकि दृश्य पदानुक्रम के भीतर एक तालिका दृश्य में सब-टेस्ट के रूप में कोशिकाएँ होती हैं जो बाद में अपने स्वयं के 'सामग्री दृश्य' होती हैं यही कारण है कि सेल प्राप्त करने के लिए आपको इस सामग्री दृश्य का पर्यवेक्षक प्राप्त करना होगा। इसके परिणामस्वरूप, यदि आपका बटन सीधे सेल के सामग्री दृश्य में एक सबव्यू में समाहित है, तो आपको इसे एक्सेस करने के लिए कई परतों में जाना होगा।

ऊपर एक ऐसा दृष्टिकोण है, लेकिन जरूरी नहीं कि सबसे अच्छा तरीका है। जब भी यह कार्यशील होता है, यह इस UITableViewCellबात का विवरण देता है कि Apple ने कभी जरूरी दस्तावेज नहीं बनाए हैं, जैसे कि यह पदानुक्रम है। इसे भविष्य में बदला जा सकता है, और इसके परिणामस्वरूप उपरोक्त कोड अच्छी तरह से अप्रत्याशित रूप से व्यवहार कर सकता है।

उपरोक्त के परिणामस्वरूप, दीर्घायु और विश्वसनीयता कारणों के लिए, मैं एक और दृष्टिकोण अपनाने की सलाह देता हूं। इस धागे में कई विकल्प सूचीबद्ध हैं, और मैं आपको नीचे पढ़ने के लिए प्रोत्साहित करता हूं, लेकिन मेरा व्यक्तिगत पसंदीदा इस प्रकार है:

अपने सेल वर्ग पर एक क्लोजर की एक संपत्ति पकड़ो, बटन की कार्रवाई विधि को लागू करें।

class MyCell: UITableViewCell {
    var button: UIButton!

    var buttonAction: ((Any) -> Void)?

    @objc func buttonPressed(sender: Any) {
        self.buttonAction?(sender)
    }
}

फिर, जब आप अपना सेल बनाते हैं, तो आप cellForRowAtIndexPathअपने बंद करने के लिए एक मूल्य प्रदान कर सकते हैं।

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! MyCell
    cell.buttonAction = { sender in
        // Do whatever you want from your button here.
    }
    // OR
    cell.buttonAction = buttonPressed(closure: buttonAction, indexPath: indexPath) // <- Method on the view controller to handle button presses.
}

अपने हैंडलर कोड को यहां ले जाकर, आप पहले से मौजूद indexPathतर्क का लाभ उठा सकते हैं । यह एक अधिक सुरक्षित दृष्टिकोण है जो ऊपर सूचीबद्ध है क्योंकि यह अनिर्दिष्ट लक्षणों पर निर्भर नहीं करता है।


2
अच्छी तरह से देखा गया। मैं एक सक्षम डेवलपर हूं, मैं वादा करता हूं;) - मेरे जवाब में संशोधन किया है।
जैकब किंग

12
यह एक बटन से सेल प्राप्त करने का उचित तरीका नहीं है। एक सेल का लेआउट पिछले कुछ वर्षों में बदल गया है और कोड इस तरह से काम करेगा जब ऐसा होगा। इस दृष्टिकोण का उपयोग न करें।
rammdy

11
यह एक बुरा उपाय है। यह UITableViewCells के बारे में विवरण मानता है कि Apple कभी भी इसके लिए सहमत नहीं हुआ है। हालांकि UITableViewCells में एक contentView संपत्ति है, इस बात की कोई गारंटी नहीं है कि contentView का पर्यवेक्षण हमेशा सेल रहेगा।
bpapa

1
@PintuRajput क्या आप कृपया अपने विचार पदानुक्रम का वर्णन मेरे लिए कर सकते हैं? आपको यह देखने की संभावना है क्योंकि आपका बटन सेल के सामग्री दृश्य का प्रत्यक्ष उप-भाग नहीं है।
जैकब किंग

2
@ आईयूट्लू मैं पूरी तरह से सहमत हूं, मैंने उत्तर में यह कहा था। मैंने और भी अधिक मजबूत समाधान का प्रस्ताव किया। मेरे द्वारा मूल को छोड़ देने का कारण यह है क्योंकि मुझे लगता है कि अन्य देवों को एक दृष्टिकोण के साथ पूरी तरह से दिखाने के लिए बेहतर है, यह उन्हें सिखाता है कि आप कुछ भी नहीं देखते हैं। :)
याकूब किंग

61

इस तरह की समस्या के लिए मेरा दृष्टिकोण सेल और टेबलव्यू के बीच एक प्रतिनिधि प्रोटोकॉल का उपयोग करना है। यह आपको सेल उपवर्ग में बटन हैंडलर रखने की अनुमति देता है, जो आपको इंटरफ़ेस बिल्डर में प्रोटोटाइप सेल में टच एक्शन हैंडलर को असाइन करने में सक्षम बनाता है, जबकि बटन कंट्रोलर लॉजिक को व्यू कंट्रोलर में रखता है।

यह दृश्य पदानुक्रम या tagसंपत्ति के उपयोग को नेविगेट करने के संभावित नाजुक दृष्टिकोण से भी बचता है , जिसमें समस्याएं होती हैं जब कोशिकाएं बदल जाती हैं (सम्मिलन, विलोपन या पुनरावर्तन के परिणामस्वरूप)

CellSubclass.swift

protocol CellSubclassDelegate: class {
    func buttonTapped(cell: CellSubclass)
}

class CellSubclass: UITableViewCell {

@IBOutlet var someButton: UIButton!

weak var delegate: CellSubclassDelegate?

override func prepareForReuse() {
    super.prepareForReuse()
    self.delegate = nil
}

@IBAction func someButtonTapped(sender: UIButton) {
    self.delegate?.buttonTapped(self)
}

ViewController.swift

class MyViewController: UIViewController, CellSubclassDelegate {

    @IBOutlet var tableview: UITableView!

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CellSubclass

        cell.delegate = self

        // Other cell setup

    } 

    //  MARK: CellSubclassDelegate

    func buttonTapped(cell: CellSubclass) {
        guard let indexPath = self.tableView.indexPathForCell(cell) else {
            // Note, this shouldn't happen - how did the user tap on a button that wasn't on screen?
            return
        }

        //  Do whatever you need to do with the indexPath

        print("Button tapped on row \(indexPath.row)")
    }
} 

buttonTappedप्रतिनिधि कार्य है और दृश्य नियंत्रक में है। मेरे उदाहरण someButtonTappedमें, सेल में एक्शन विधि है
पॉलव 11

@ paulw11 मेरे पास सेल है कोई सदस्य बटन नहीं है इस तरीके से टैप किया गया@IBAction func someButtonTapped(sender: UIButton) { self.delegate?.buttonTapped(self) }
EI Captain v2.0

1
यह एक बहुत अच्छा समाधान है (दोनों के पास वर्तमान में अधिक वोटों के साथ उतना ही बुरा है, जितना कि पर्यवेक्षक को देख टैग का उपयोग करके) लेकिन यह बहुत अधिक अतिरिक्त कोड जोड़ने जैसा लगता है।
bpapa

2
यह सही समाधान है और स्वीकृत उत्तर होना चाहिए। यह टैग की संपत्ति का दुरुपयोग नहीं करता है, कोशिकाओं के निर्माण का अनुमान नहीं लगाता है (जो कि Apple द्वारा आसानी से बदला जा सकता है) और अभी भी काम करेगा (कोई अतिरिक्त कोडिंग के साथ) जब कोशिकाओं को ले जाया जाता है या मौजूदा कोशिकाओं के बीच में नई कोशिकाओं को जोड़ा जाता है।
रोबोट बिल्ली

1
@ पॉल्व 11 मैंने शुरू में सोचा था कि यह बहुत कोड था, लेकिन यह पहले की तुलना में बहुत अधिक लचीला साबित हुआ है। इस मजबूत समाधान को पोस्ट करने के लिए धन्यवाद।
एड्रियन

53

अद्यतन : बटन वाले सेल के इंडेक्सपाथ को प्राप्त करना (अनुभाग और पंक्ति दोनों):

बटन स्थिति का उपयोग करना

अपनी buttonTappedविधि के अंदर , आप बटन की स्थिति को पकड़ सकते हैं, इसे तालिका दृश्य में एक समन्वय में परिवर्तित कर सकते हैं, फिर उस समन्वय पर पंक्ति का indexPath प्राप्त कर सकते हैं।

func buttonTapped(_ sender:AnyObject) {
    let buttonPosition:CGPoint = sender.convert(CGPoint.zero, to:self.tableView)
    let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
}

नोट : कभी-कभी आप एक किनारे मामले में भाग सकते हैं जब फ़ंक्शन का उपयोग करते हुए एक बिंदु पर एक पंक्ति के लिए view.convert(CGPointZero, to:self.tableView)खोज nilकिया जाता है, भले ही वहां एक टेबल व्यू हो। इसे ठीक करने के लिए, एक वास्तविक निर्देशांक पास करने का प्रयास करें जो मूल से थोड़ा ऑफसेट हो, जैसे:

let buttonPosition:CGPoint = sender.convert(CGPoint.init(x: 5.0, y: 5.0), to:self.tableView)

पिछला उत्तर: टैग प्रॉपर्टी का उपयोग करके (केवल रिटर्न रो)

बल्कि superview पेड़ों में चढ़ाई सेल कि UIButton रखती है, वहाँ एक सुरक्षित, अधिक दोहराने योग्य तकनीक button.tag संपत्ति ऊपर एंटोनियो ने उल्लेख उपयोग, में वर्णित है के लिए सूचक हड़पने के लिए की तुलना में इस सवाल का जवाब है, और नीचे दिखाया गया है:

में cellForRowAtIndexPath:आप टैग गुण सेट:

button.tag = indexPath.row
button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)

फिर, buttonClicked:फ़ंक्शन में, आप उस टैग को इंडेक्सपाथ की पंक्ति को पकड़ने के लिए संदर्भित करते हैं जहां बटन स्थित है:

func buttonClicked(sender:UIButton) {
    let buttonRow = sender.tag
}

मैं इस पद्धति को पसंद करता हूं क्योंकि मैंने पाया है कि सुपरविवे पेड़ों में झूलना एक ऐप को डिजाइन करने का एक जोखिम भरा तरीका हो सकता है। इसके अलावा, उद्देश्य-सी के लिए मैंने इस तकनीक का उपयोग अतीत में किया है और परिणाम से खुश है।


5
यह इसे करने का एक अच्छा तरीका है, और मैं इसे दोहराऊंगा ताकि आपका प्रतिनिधि थोड़ा शुरू कर सके, हालांकि इसका एकमात्र दोष यह है कि यह indexPath.section को एक्सेस नहीं देता है यदि यह आवश्यक है। हालांकि महान जवाब!
जैकब किंग

धन्यवाद जैकब! मैं प्रतिनिधि कर्म की सराहना करता हूं। यदि आप (के रूप में टैग संपत्ति को रीसेट किए बिना ) के indexPath.sectionअतिरिक्त प्राप्त करना चाहते थे , तो आप केवल टैग को बदल सकते थे , और फिर फ़ंक्शन में आप का उपयोग करके और दोनों का उपयोग कर सकते थे । indexPath.rowindexPath.sectioncellForRowAtIndexPath:button.tag = indexPathbuttonClicked:sender.tag.rowsender.tag.section
आयरन जॉन बोनी

1
क्या यह एक नई विशेषता है, क्योंकि मुझे यकीन है कि मुझे टैग प्रॉपर्टी टाइप के होने का स्मरण है, जब तक कि स्विफ्ट 2.3 में नहीं बदला गया है, तब तक कोई भी प्रकार टाइप नहीं किया जाता है?
याकूब राजा

@JacobKing तुम सही हो! मेरा बुरा मैं पूरी तरह से उस टिप्पणी को लिखते समय फैला था और सोच रहा था कि टैग किसी भी प्रकार का था। Derp - मुझे कोई आपत्ति नहीं है। यह उपयोगी होगा यदि आप एक टैग के रूप में इंडेक्सपाथ को पारित कर सकते हैं ...
आयरन जॉन बोन्नी

3
वास्तव में एक अच्छा दृष्टिकोण भी नहीं है। एक बात के लिए, यह केवल टेबल व्यू में काम करेगा जहां एक ही खंड है।
bpapa

16

किसी दृश्य के लिए सेल लाने के लिए UITableView के एक्सटेंशन का उपयोग करें:


@ एक प्रतिनिधि प्रॉपर्टी के साथ कस्टम सेल प्रकार स्थापित करने का पॉल्व 11 का जवाब, टेबल व्यू को संदेश भेजने का एक अच्छा तरीका है, लेकिन इसे स्थापित करने के लिए एक निश्चित राशि की आवश्यकता होती है।

मुझे लगता है कि टेबल व्यू सेल की व्यू पदानुक्रम चलना सेल की तलाश करना एक बुरा विचार है। यह नाजुक है - यदि आप बाद में लेआउट उद्देश्यों के लिए एक दृश्य में अपने बटन को संलग्न करते हैं, तो उस कोड के टूटने की संभावना है।

दृश्य टैग का उपयोग करना भी नाजुक है। आपको सेल बनाते समय टैग सेट करना याद रखना होगा, और यदि आप उस दृष्टिकोण का उपयोग एक व्यू कंट्रोलर में करते हैं जो किसी अन्य उद्देश्य के लिए व्यू टैग का उपयोग करता है तो आपके पास डुप्लिकेट टैग नंबर हो सकते हैं और आपका कोड अपेक्षित रूप से काम करने में विफल हो सकता है।

मैंने UITableView के लिए एक एक्सटेंशन बनाया है जो आपको टेबल व्यू सेल में शामिल किसी भी दृश्य के लिए इंडेक्सपाथ प्राप्त करने देता है। Optionalयदि रिटर्न वास्तव में टेबल व्यू सेल में नहीं आता है तो यह शून्य हो जाएगा। नीचे यह संपूर्ण विस्तार फ़ाइल है। आप बस इस फ़ाइल को अपनी परियोजना में रख सकते हैं और फिर शामिल indexPathForView(_:)पद्धति का उपयोग कर सकते हैं ताकि इंडेक्सपाथ को ढूंढ सकें जिसमें कोई भी दृश्य हो।

//
//  UITableView+indexPathForView.swift
//  TableViewExtension
//
//  Created by Duncan Champney on 12/23/16.
//  Copyright © 2016-2017 Duncan Champney.
//  May be used freely in for any purpose as long as this 
//  copyright notice is included.

import UIKit

public extension UITableView {
  
  /**
  This method returns the indexPath of the cell that contains the specified view
   
   - Parameter view: The view to find.
   
   - Returns: The indexPath of the cell containing the view, or nil if it can't be found
   
  */
  
    func indexPathForView(_ view: UIView) -> IndexPath? {
        let center = view.center
        let viewCenter = self.convert(center, from: view.superview)
        let indexPath = self.indexPathForRow(at: viewCenter)
        return indexPath
    }
}

इसका उपयोग करने के लिए, आप IBA में विधि को एक बटन के लिए कह सकते हैं जो एक सेल में निहित है:

func buttonTapped(_ button: UIButton) {
  if let indexPath = self.tableView.indexPathForView(button) {
    print("Button tapped at indexPath \(indexPath)")
  }
  else {
    print("Button indexPath not found")
  }
}

(ध्यान दें कि indexPathForView(_:)फ़ंक्शन केवल तभी काम करेगा जब दृश्य ऑब्जेक्ट पास किया गया है, जो वर्तमान में ऑन-स्क्रीन एक सेल द्वारा सम्‍मिलित है। यह उचित है, क्योंकि ऑन-स्क्रीन ऐसा नहीं है जो वास्तव में किसी विशिष्ट indexPath से संबंधित नहीं है; यह संभव है। सेल पुनर्नवीनीकरण होने पर एक अलग इंडेक्सपाथ को सौंपा जाए।)

संपादित करें:

आप एक कामकाजी डेमो प्रोजेक्ट डाउनलोड कर सकते हैं जो ऊपर दिए गए एक्सटेंशन का उपयोग जीथब: टेबल व्यूएक्स्टेंशन.जीट से करता है


धन्यवाद मैं एक सेल में एक textview के indexPath प्राप्त करने के लिए विस्तार का इस्तेमाल किया - पूरी तरह से काम किया।
जेरेमी एंड्रयूज

9

के लिये Swift2.1

मुझे ऐसा करने का एक तरीका मिला, उम्मीद है, यह मदद करेगा।

let point = tableView.convertPoint(CGPoint.zero, fromView: sender)

    guard let indexPath = tableView.indexPathForRowAtPoint(point) else {
        fatalError("can't find point in tableView")
    }

यदि त्रुटि चलती है तो इसका क्या मतलब है? तालिका दृश्य में बिंदु नहीं मिल पाने के कुछ कारण क्या हैं?
OOProg

यह (या समान, यूआईवीवाईई कन्वर्जिंग विधियों का उपयोग करके) स्वीकृत उत्तर होना चाहिए। यह निश्चित नहीं है कि यह वर्तमान में # 4 क्यों है, क्योंकि यह एक टेबल व्यू के निजी उत्तराधिकार के बारे में धारणा नहीं बनाता है, यह टैग संपत्ति (लगभग हमेशा एक बुरा विचार) का उपयोग नहीं करता है, और इसमें बहुत अधिक अतिरिक्त कोड शामिल नहीं है।
bpapa

9

स्विफ्ट 4 समाधान:

आपके पास एक बटन (myButton) या सेल में कोई अन्य दृश्य है। इस तरह से CellForRowAt में टैग असाइन करें

cell.myButton.tag = indexPath.row

अब आप टैपफंक्शन या किसी अन्य में। इसे इस तरह से प्राप्त करें और इसे स्थानीय चर में सहेजें।

currentCellNumber = (sender.view?.tag)!

इसके बाद आप चुनिंदा बटन के indexPath.row को प्राप्त करने के लिए इस currentCellNumber का कहीं भी उपयोग कर सकते हैं।

का आनंद लें!


यह दृष्टिकोण काम करता है, लेकिन मेरे जवाब में बताए अनुसार टैग्स नाजुक हैं। उदाहरण के लिए, एक साधारण पूर्णांक टैग सेक्शन टेबल व्यू के लिए काम नहीं करेगा। (एक IndexPath यह 2 पूर्णांक।) मेरा दृष्टिकोण हमेशा काम करेगा, और बटन (या अन्य टैप करने योग्य दृश्य) में एक टैग स्थापित करने की कोई आवश्यकता नहीं है।
डंकन सी

6

स्विफ्ट 4 में, बस इसका उपयोग करें:

func buttonTapped(_ sender: UIButton) {
        let buttonPostion = sender.convert(sender.bounds.origin, to: tableView)

        if let indexPath = tableView.indexPathForRow(at: buttonPostion) {
            let rowIndex =  indexPath.row
        }
}

सबसे स्वच्छ उत्तर, चयनित होना चाहिए। केवल ध्यान देने योग्य बात यह है कि tableViewएक आउटलेट वैरिएबल है जिसे इस उत्तर के काम करने से पहले संदर्भित किया जाना चाहिए।
10000RubyPools

आकर्षण जैसा काम !!
पार्थपतेल

4

बहुत सरल हो रही सूचकांक पथ स्विफ्ट 4, 5

let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! Cell
cell.btn.tag = indexPath.row
cell.btn.addTarget(self, action: "buttonTapped:", forControlEvents: 
UIControlEvents.TouchUpInside)

इंडेक्सपथ इनसाइड बीटीएन कैसे प्राप्त करें:

func buttonTapped(_ sender: UIButton) {
     print(sender.tag)  
}

3

चूंकि ईवेंट हैंडलर का प्रेषक स्वयं बटन है, इसलिए मैं बटन की tagसंपत्ति का उपयोग सूचकांक को स्टोर करने के लिए करूंगा, जिसे प्रारंभ में प्रारंभ किया जाएगाcellForRowAtIndexPath

लेकिन थोड़े और काम के साथ मैं पूरी तरह से अलग तरीके से काम करूंगा। यदि आप एक कस्टम सेल का उपयोग कर रहे हैं, तो इस तरह से मैं समस्या का सामना करूंगा:

  • कस्टम तालिका सेल में 'indexPath` गुण जोड़ें
  • इसे आरंभ करें cellForRowAtIndexPath
  • नल नियंत्रक से सेल कार्यान्वयन पर ले जाएँ
  • इंडेक्स पथ को पार करते हुए, नल नियंत्रक के बारे में व्यू कंट्रोलर को सूचित करने के लिए डेलिगेशन पैटर्न का उपयोग करें

एंटोनियो, मेरे पास एक कस्टम सेल है और इसे अपने तरीके से करना पसंद करेंगे। हालांकि, यह काम नहीं कर रहा है। मैं चाहता हूं कि मेरी 'स्वाइप टू डिलीट बटन' कोड को चला जाए, जो कि टेबल व्यू कम्यूटिंग स्टाइल विधि है। मैंने उस कोड को mainVC क्लास से हटा दिया और उसे customCell क्लास में डाल दिया, लेकिन अब कोड काम नहीं करता। मैं क्या खो रहा हूँ?
डेव जी

मुझे लगता है कि एक्स वर्गों के साथ एक सेल के इंडेक्सपाथ को प्राप्त करने का यह सबसे अच्छा तरीका है, हालांकि मुझे एमवीसी दृष्टिकोण में बुलेट अंक 3 और 4 की आवश्यकता नहीं
एडवर्ड

2

एक प्रतिनिधि कॉलबैक का उपयोग करने के पॉलवे 11 के सुझाव को देखने के बाद, मैं इसे थोड़ा विस्तृत करना चाहता था / एक और सुझाव दिया, इसी तरह का सुझाव। क्या आपको उस प्रतिनिधि पैटर्न का उपयोग नहीं करना चाहिए जिसे आप निम्न प्रकार से स्विफ्ट में बंद कर सकते हैं:

आपका सेल वर्ग:

class Cell: UITableViewCell {
    @IBOutlet var button: UIButton!

    var buttonAction: ((sender: AnyObject) -> Void)?

    @IBAction func buttonPressed(sender: AnyObject) {
        self.buttonAction?(sender)
    }
}

आपका cellForRowAtIndexPathतरीका:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! Cell
    cell.buttonAction = { (sender) in
        // Do whatever you want from your button here.
    }
    // OR
    cell.buttonAction = buttonPressed // <- Method on the view controller to handle button presses.
}

2

मैंने एक मॉडल वर्ग का उपयोग करके tableView और संग्रह दृश्य में किसी भी सेल को प्रबंधित करने के लिए उपयोग करने का एक बहुत आसान तरीका पाया और यह पूरी तरह से एक काम है।

अब इसे संभालने के लिए वास्तव में बहुत बेहतर तरीका है। यह सेल और मूल्य को प्रबंधित करने के लिए काम करेगा।

यहाँ मेरा आउटपुट (स्क्रीनशॉट) है इसलिए इसे देखें:

यहां छवि विवरण दर्ज करें

  1. मॉडल वर्ग बनाने के लिए इसका बहुत सरल , कृपया नीचे दी गई प्रक्रिया का पालन करें। नाम के साथ स्विफ्ट क्लास बनाएं RNCheckedModel, नीचे जैसा कोड लिखें।
class RNCheckedModel: NSObject {

    var is_check = false
    var user_name = ""

    }
  1. अपना सेल क्लास बनाएं
class InviteCell: UITableViewCell {

    @IBOutlet var imgProfileImage: UIImageView!
    @IBOutlet var btnCheck: UIButton!
    @IBOutlet var lblName: UILabel!
    @IBOutlet var lblEmail: UILabel!
    }
  1. और अंत में अपने में मॉडल क्लास का उपयोग UIViewController जब आप अपने का उपयोग UITableView
    class RNInviteVC: UIViewController, UITableViewDelegate, UITableViewDataSource {


    @IBOutlet var inviteTableView: UITableView!
    @IBOutlet var btnInvite: UIButton!

    var checkArray : NSMutableArray = NSMutableArray()
    var userName : NSMutableArray = NSMutableArray()

    override func viewDidLoad() {
        super.viewDidLoad()
        btnInvite.layer.borderWidth = 1.5
        btnInvite.layer.cornerRadius = btnInvite.frame.height / 2
        btnInvite.layer.borderColor =  hexColor(hex: "#512DA8").cgColor

        var userName1 =["Olivia","Amelia","Emily","Isla","Ava","Lily","Sophia","Ella","Jessica","Mia","Grace","Evie","Sophie","Poppy","Isabella","Charlotte","Freya","Ruby","Daisy","Alice"]


        self.userName.removeAllObjects()
        for items in userName1 {
           print(items)


            let model = RNCheckedModel()
            model.user_name = items
            model.is_check = false
            self.userName.add(model)
        }
      }
     @IBAction func btnInviteClick(_ sender: Any) {

    }
       func tableView(_ tableView: UITableView, numberOfRowsInSection 
       section: Int) -> Int {
        return userName.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: InviteCell = inviteTableView.dequeueReusableCell(withIdentifier: "InviteCell", for: indexPath) as! InviteCell

        let image = UIImage(named: "ic_unchecked")
        cell.imgProfileImage.layer.borderWidth = 1.0
        cell.imgProfileImage.layer.masksToBounds = false
        cell.imgProfileImage.layer.borderColor = UIColor.white.cgColor
        cell.imgProfileImage.layer.cornerRadius =  cell.imgProfileImage.frame.size.width / 2
        cell.imgProfileImage.clipsToBounds = true

        let model = self.userName[indexPath.row] as! RNCheckedModel
        cell.lblName.text = model.user_name

        if (model.is_check) {
            cell.btnCheck.setImage(UIImage(named: "ic_checked"), for: UIControlState.normal)
        }
        else {
            cell.btnCheck.setImage(UIImage(named: "ic_unchecked"), for: UIControlState.normal)
        }

        cell.btnCheck.tag = indexPath.row
        cell.btnCheck.addTarget(self, action: #selector(self.btnCheck(_:)), for: .touchUpInside)

        cell.btnCheck.isUserInteractionEnabled = true

    return cell

    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 80

    }

    @objc func btnCheck(_ sender: UIButton) {

        let tag = sender.tag
        let indexPath = IndexPath(row: tag, section: 0)
        let cell: InviteCell = inviteTableView.dequeueReusableCell(withIdentifier: "InviteCell", for: indexPath) as! InviteCell

        let model = self.userName[indexPath.row] as! RNCheckedModel

        if (model.is_check) {

            model.is_check = false
            cell.btnCheck.setImage(UIImage(named: "ic_unchecked"), for: UIControlState.normal)

            checkArray.remove(model.user_name)
            if checkArray.count > 0 {
                btnInvite.setTitle("Invite (\(checkArray.count))", for: .normal)
                print(checkArray.count)
                UIView.performWithoutAnimation {
                    self.view.layoutIfNeeded()
                }
            } else {
                btnInvite.setTitle("Invite", for: .normal)
                UIView.performWithoutAnimation {
                    self.view.layoutIfNeeded()
                }
            }

        }else {

            model.is_check = true
            cell.btnCheck.setImage(UIImage(named: "ic_checked"), for: UIControlState.normal)

            checkArray.add(model.user_name)
            if checkArray.count > 0 {
                btnInvite.setTitle("Invite (\(checkArray.count))", for: .normal)
                UIView.performWithoutAnimation {
                self.view.layoutIfNeeded()
                }
            } else {
                 btnInvite.setTitle("Invite", for: .normal)
            }
        }

        self.inviteTableView.reloadData()
    }

    func hexColor(hex:String) -> UIColor {
        var cString:String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()

        if (cString.hasPrefix("#")) {
            cString.remove(at: cString.startIndex)
        }

        if ((cString.count) != 6) {
            return UIColor.gray
        }

        var rgbValue:UInt32 = 0
        Scanner(string: cString).scanHexInt32(&rgbValue)

        return UIColor(
            red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
            green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
            blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
            alpha: CGFloat(1.0)
        )
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()

    }

     }

1

मैंने टेबलव्यू से बिंदु प्राप्त करने और indexPathForRowAtPoint विधि को indexPath प्राप्त करने के लिए कनवर्ज़न विधि का उपयोग किया

 @IBAction func newsButtonAction(sender: UIButton) {
        let buttonPosition = sender.convertPoint(CGPointZero, toView: self.newsTableView)
        let indexPath = self.newsTableView.indexPathForRowAtPoint(buttonPosition)
        if indexPath != nil {
            if indexPath?.row == 1{
                self.performSegueWithIdentifier("alertViewController", sender: self);
            }   
        }
    }

1

# कॉल करने के लिए #selector का उपयोग करने का प्रयास करें

            cell.editButton.tag = indexPath.row
        cell.editButton.addTarget(self, action: #selector(editButtonPressed), for: .touchUpInside)

इस तरह आप indexBath को editButtonPressed विधि के अंदर एक्सेस कर सकते हैं

func editButtonPressed(_ sender: UIButton) {

print(sender.tag)//this value will be same as indexpath.row

}

सबसे उपयुक्त उत्तर
अमलेंदु कर

नहीं, उपयोगकर्ता द्वारा कोशिकाओं को जोड़ने या हटाने पर टैग बंद हो जाएंगे।
कोएन

1

मेरे मामले में मेरे पास कई खंड हैं और दोनों खंड और पंक्ति सूचकांक महत्वपूर्ण है, इसलिए ऐसे मामले में मैंने सिर्फ यूआईब्यूटन पर एक संपत्ति बनाई जो मैंने सेल इंडेक्सपाथ को इस तरह सेट किया:

fileprivate struct AssociatedKeys {
    static var index = 0
}

extension UIButton {

    var indexPath: IndexPath? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.index) as? IndexPath
        }
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.index, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

फिर इस तरह से सेलफ़ोररॉव में संपत्ति सेट करें:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! Cell
    cell.button.indexPath = indexPath
}

उसके बाद handleTapAction में आप इस तरह indexPath प्राप्त कर सकते हैं:

@objc func handleTapAction(_ sender: UIButton) {
    self.selectedIndex = sender.indexPath

}

1

स्विफ्ट 4 और 5

विधि 1 प्रोटोकॉल प्रतिनिधि का उपयोग कर

उदाहरण के लिए, आपके पास एक UITableViewCellनाम हैMyCell

class MyCell: UITableViewCell {
    
    var delegate:MyCellDelegate!
    
    @IBAction private func myAction(_ sender: UIButton){
        delegate.didPressButton(cell: self)
    }
}

अब एक बनाएँ protocol

protocol MyCellDelegate {
    func didPressButton(cell: UITableViewCell)
}

अगला चरण, का एक एक्सटेंशन बनाएं UITableView

extension UITableView {
    func returnIndexPath(cell: UITableViewCell) -> IndexPath?{
        guard let indexPath = self.indexPath(for: cell) else {
            return nil
        }
        return indexPath
    }
}

अपने UIViewControllerकार्यान्वयन में प्रोटोकॉलMyCellDelegate

class ViewController: UIViewController, MyCellDelegate {
     
    func didPressButton(cell: UITableViewCell) {
        if let indexpath = self.myTableView.returnIndexPath(cell: cell) {
              print(indexpath)
        }
    }
}

विधि 2 बंद का उपयोग कर

में UIViewController

override func viewDidLoad() {
        super.viewDidLoad()
       //using the same `UITableView extension` get the IndexPath here
        didPressButton = { cell in
            if let indexpath = self.myTableView.returnIndexPath(cell: cell) {
                  print(indexpath)
            }
        }
    }
 var didPressButton: ((UITableViewCell) -> Void)

class MyCell: UITableViewCell {

    @IBAction private func myAction(_ sender: UIButton){
        didPressButton(self)
    }
}

नोट: - यदि आप UICollectionViewindexPath प्राप्त करना चाहते हैं तो आप इसका उपयोग कर सकते हैं UICollectionView extensionऔर उपरोक्त चरणों को दोहरा सकते हैं

extension UICollectionView {
    func returnIndexPath(cell: UICollectionViewCell) -> IndexPath?{
        guard let indexPath = self.indexPath(for: cell) else {
            return nil
        }
        return indexPath
    }
}

0

स्विफ्ट 3. में ब्रेसिज़ की लंबी श्रृंखला से बचने के लिए, गार्ड के बयानों का भी इस्तेमाल किया गया।

func buttonTapped(sender: UIButton) {
    guard let cellInAction = sender.superview as? UITableViewCell else { return }
    guard let indexPath = tableView?.indexPath(for: cellInAction) else { return }

    print(indexPath)
}

यह काम नहीं करेगा। बटन का सुपरवाइज सेल नहीं होगा।
धांधली

यह काम करता है। केवल एक चीज जो आपको ध्यान से होनी चाहिए वह यह है कि हर किसी का दृष्टिकोण अलग है। यह प्रेषक हो सकता है। Superview, प्रेषक। superview.superview या प्रेषक। superview.superview.superview। लेकिन यह वास्तव में अच्छी तरह से काम करता है।
सीन

0

कभी-कभी बटन UITableViewCell के किसी अन्य दृश्य के अंदर हो सकता है। उस स्थिति में पर्यवेक्षक। Superview सेल ऑब्जेक्ट नहीं दे सकता है और इसलिए indexPath शून्य होगा।

उस मामले में हमें तब तक पर्यवेक्षण करना चाहिए जब तक कि हमें सेल ऑब्जेक्ट नहीं मिल जाता है।

पर्यवेक्षण द्वारा सेल वस्तु प्राप्त करने का कार्य

func getCellForView(view:UIView) -> UITableViewCell?
{
    var superView = view.superview

    while superView != nil
    {
        if superView is UITableViewCell
        {
            return superView as? UITableViewCell
        }
        else
        {
            superView = superView?.superview
        }
    }

    return nil
}

अब हम नीचे दिए गए बटन टैप पर indexPath प्राप्त कर सकते हैं

@IBAction func tapButton(_ sender: UIButton)
{
    let cell = getCellForView(view: sender)
    let indexPath = myTabelView.indexPath(for: cell)
}

0
// CustomCell.swift

protocol CustomCellDelegate {
    func tapDeleteButton(at cell: CustomCell)
}

class CustomCell: UICollectionViewCell {
    
    var delegate: CustomCellDelegate?
    
    fileprivate let deleteButton: UIButton = {
        let button = UIButton(frame: .zero)
        button.setImage(UIImage(named: "delete"), for: .normal)
        button.addTarget(self, action: #selector(deleteButtonTapped(_:)), for: .touchUpInside)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()
    
    @objc fileprivate func deleteButtonTapped(_sender: UIButton) {
        delegate?.tapDeleteButton(at: self)
    }
    
}

//  ViewController.swift

extension ViewController: UICollectionViewDataSource {

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: customCellIdentifier, for: indexPath) as? CustomCell else {
            fatalError("Unexpected cell instead of CustomCell")
        }
        cell.delegate = self
        return cell
    }

}

extension ViewController: CustomCellDelegate {

    func tapDeleteButton(at cell: CustomCell) {
        // Here we get the indexPath of the cell what we tapped on.
        let indexPath = collectionView.indexPath(for: cell)
    }

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.