Как может tableview.window nil, когда я использую tableViewController? [Дубликат]

Когда ваши пути include разные

Ошибки компоновщика могут произойти, если заголовочный файл и связанная с ним общая библиотека (файл .lib) не синхронизируются. Позволь мне объяснить.

Как работают линкеры? Линкер соответствует объявлению функции (объявленному в заголовке) с его определением (в общей библиотеке) путем сравнения их подписи. Вы можете получить ошибку компоновщика, если компоновщик не найдет определение функции, которое идеально подходит.

Возможно ли получить ошибку компоновщика, даже если объявление и определение, похоже, совпадают? Да! Они могут выглядеть одинаково в исходном коде, но это действительно зависит от того, что видит компилятор. По сути, вы можете столкнуться с такой ситуацией:

// header1.h
typedef int Number;
void foo(Number);

// header2.h
typedef float Number;
void foo(Number); // this only looks the same lexically

Обратите внимание, что хотя обе декларации функций выглядят одинаково в исходном коде, но они действительно различаются в зависимости от компилятора.

Вы можете спросить, как это получается в такой ситуации? Включите пути, конечно! Если при компиляции разделяемой библиотеки путь include приводит к header1.h, и вы в конечном итоге используете header2.h в своей собственной программе, вы оставите царапины на своем заголовке, задаваясь вопросом, что произошло (каламбур).

Пример того, как это может произойти в реальном мире, объясняется ниже.

Дальнейшая разработка с примером

У меня есть два проекта: graphics.lib и main.exe. Оба проекта зависят от common_math.h. Предположим, что библиотека экспортирует следующую функцию:

// graphics.lib    
#include "common_math.h" 

void draw(vec3 p) { ... } // vec3 comes from common_math.h

И затем вы идете вперед и включаете библиотеку в свой собственный проект.

// main.exe
#include "other/common_math.h"
#include "graphics.h"

int main() {
    draw(...);
}

Boom! Вы получаете ошибку компоновщика, и вы понятия не имеете, почему она терпит неудачу. Причина в том, что общая библиотека использует разные версии одного и того же include common_math.h (я сделал это очевидным здесь в этом примере, включив другой путь, но это может быть не всегда так очевидно. Возможно, путь include отличается в настройки компилятора).

Обратите внимание, что в этом примере компоновщик сказал бы вам, что не смог найти draw(), когда на самом деле вы знаете, что он явно экспортируется библиотекой. Вы могли часами царапать себе голову, думая, что пошло не так. Дело в том, что компоновщик видит другую подпись, потому что типы параметров немного отличаются. В этом примере vec3 является другим типом в обоих проектах в отношении компилятора. Это может произойти из-за того, что они происходят из двух немного разных файлов include (возможно, включенные файлы поступают из двух разных версий библиотеки).

Отладка компоновщика

DUMPBIN - ваш друг, если вы используете Visual Studio. Я уверен, что другие компиляторы имеют другие подобные инструменты.

Процесс выглядит следующим образом:

  1. Обратите внимание на странное искаженное имя, указанное в ошибке компоновщика. (например, draw @ graphics @ XYZ).
  2. Выгрузите экспортированные символы из библиотеки в текстовый файл.
  3. Найдите экспортированный символ, представляющий интерес, и обратите внимание, что искаженное имя
  4. Обратите внимание на то, почему искаженные имена оказались разными. Вы могли бы видеть, что типы параметров различны, хотя они выглядят одинаково в исходном коде.
  5. Причина, почему они разные. В приведенном выше примере они различаются из-за разных файлов include.

[1] По проекту я имею в виду набор исходных файлов, которые связаны друг с другом для создания либо библиотеки, либо исполняемого файла .

РЕДАКТИРОВАТЬ 1: Переписать первый раздел, который будет легче понять. Пожалуйста, прокомментируйте ниже, чтобы сообщить мне, нужно ли что-то еще исправлять. Спасибо!

13
задан jonas vermeulen 2 September 2013 в 17:55
поделиться

6 ответов

Проблема заключается в том, что представление для UITableViewController является UITableView, поэтому вы не можете добавлять подпрограммы к контроллеру поверх таблицы.

Я бы рекомендовал переключиться с UITableViewController к простому UIViewController, содержащему UITableView. Таким образом, основной вид контроллера представляет собой обычную UIView, которая содержит таблицу, и вы можете добавить subviews к основному UIView, и они будут помещены поверх табличного представления.

31
ответ дан redent84 25 August 2018 в 10:51
поделиться

Решение Swift / Storyboard

Примечание. В приведенном ниже коде предполагается, что у пользователя есть настраиваемый вид (ratingView в моем случае), который должен быть представлен через UITableView.

Я прочитал много ответов на этот и похожие вопросы о SO . Другие ответы из этих источников работали в разной степени для меня (например, просмотр загружен, но не показан или недоступен, ...). Я использую Swift 2.0+, и я использую полное решение для этого, используя UITableViewController.

Создайте выход в панель навигации и представление, которое вы хотите использовать для просмотра таблицы.

//MARK:Outlets
@IBOutlet weak var navBar:UINavigationBar!
@IBOutlet var ratingView: MNGStarRating!

В моем случае я также хотел анимировать представление по представлению таблицы, поэтому я использовал переменную класса, чтобы удерживать ссылку на точку перегиба и точку над сценой (вне экрана).

var centerYInflection:NSLayoutConstraint!
var aPointAboveScene = -(max(UIScreen.mainScreen().bounds.width,UIScreen.mainScreen().bounds.height) * 2.0)

Затем в viewDidLoad я вызвал функцию (configureRatingViewAutoLayout), которая настраивает и добавляет ограничения для нового представления, которые будут анимированы над представлением таблицы.

func configureRatingViewAutoLayout() {
    //REQUIRED    
    self.navBar.superview?.addSubview(self.ratingView)

    var newConstraints:[NSLayoutConstraint] = []
    newConstraints.append(self.ratingView.leadingAnchor.constraintEqualToAnchor(self.view.leadingAnchor,constant: 10)) 
    newConstraints.append(self.ratingView.trailingAnchor.constraintEqualToAnchor(self.view.trailingAnchor,constant: 10))
    newConstraints.append(self.ratingView.centerXAnchor.constraintEqualToAnchor(self.view.centerXAnchor))

    //hides the rating view above the scene
    self.centerYInflection = self.ratingView.centerYAnchor.constraintEqualToAnchor(self.view.centerYAnchor, constant: self.aPointAboveScene)

    //the priority must be set below 1000 if you intend to change it after it has been added to a view
    self.centerYInflection.priority = 750
    newConstraints.append(self.centerYInflection)

    //constraints must be added to the container view of the two items
    self.ratingView.superview?.addConstraints(newConstraints)

}

Nota Bene - на UITableViewController; self.view - это self.tableView. Они указывают на одно и то же, поэтому я думаю, что можно также использовать ссылку self.tableView выше.

Когда-то позже ... В ответ на событие UIControl я вызываю этот метод.

@IBAction func toggleRatingView (sender:AnyObject?){

    //REQUIRED
    self.ratingView.superview?.layoutIfNeeded()

    UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.37, initialSpringVelocity: 0.99, options: [.CurveEaseOut], animations: { () -> Void in

        if CGRectContainsRect(self.view.frame, self.ratingView.frame) {

            //in frame ~ animate away
            //I play a sound to alert the user something is happening 

            self.centerYInflection.constant = self.aPointAboveScene
            self.centerYInflection.priority = UILayoutPriority(950)
            //I disable portions of the UI
            self.disableUIElements(nil)



        } else {

            //out of frame ~ animate in
            //I play a different sound here                

            self.centerYInflection.constant = 0
            self.centerYInflection.priority = UILayoutPriority(950)

            //I enable the UI fully
            self.enableUIElements(nil)


        }
        //REQUIRED
        self.ratingView.superview?.setNeedsLayout()
        self.ratingView.superview?.layoutIfNeeded()


        }) { (success) -> Void in

            //do something else

    }

}

Эти вспомогательные методы могут быть сконфигурированы для управления доступом к элементам вашей сцены во время представления представления.

func disableUIElements(sender:AnyObject?) {
    //UI

}
func enableUIElements(sender:AnyObject?) {

    //UI

}

Предостережения

Мое представление - это пользовательский вид в раскадровке (сидящий за пределами таблицы, но подключенный к контроллеру TableView). Представление имеет требуемый атрибут времени выполнения пользователя, определенный layer.zPosition, при значении Number, установленном на 2 (это гарантирует, что оно отображается перед UITableView).

Можно также попробовать играть с помощью метода bringSubviewToFront: и sendSubviewToBack: если вы не хотите устанавливать zPosition (я думаю, что zPosition проще использовать)

1
ответ дан Community 25 August 2018 в 10:51
поделиться
UIWindow* window = [[UIApplication sharedApplication].delegate.window;
[window addSubview: your-overlayview];
2
ответ дан jianpx 25 August 2018 в 10:51
поделиться

Вы можете попытаться добавить представление в окно, а не вставить его в виде таблицы следующим образом:

UIWindow* mainWindow = [[UIApplication sharedApplication] keyWindow];
[mainWindow addSubview: overlayview];
3
ответ дан jonas vermeulen 25 August 2018 в 10:51
поделиться

Вы можете использовать self.navigationController.view в качестве представления для добавления subview.

37
ответ дан sagus_helgy 25 August 2018 в 10:51
поделиться

Попробуйте подключить кнопку внизу кнопки TableViewController

в качестве переменной

   var submitButton:UIButton!

и в viewDidLoad

    submitButton = UIButton(frame: CGRect(x: 5, y: UIScreen.main.bounds.size.height - 50 , width: UIScreen.main.bounds.size.width - 10 , height: 50))        
    submitButton.backgroundColor = UIColor.init(red: 180/255, green: 40/255, blue: 56/255, alpha: 1.0)
    submitButton.setTitle("Submit", for: .normal)
    submitButton.titleLabel?.font = UIFont(name: "Arial", size: 15)
    submitButton.titleLabel?.textColor = .white
    submitButton.addTarget(self, action: #selector(submit), for: .touchUpInside)
    submitButton.layer.cornerRadius = 5        
    self.view.addSubview(submitButton)

и реализовать этот метод

 override func scrollViewDidScroll(_ scrollView: UIScrollView) {

  submitButton.frame = CGRect.init(x: submitButton.frame.origin.x, y:  UIScreen.main.bounds.size.height + scrollView.contentOffset.y - 50 , width: submitButton.frame.width, height: submitButton.frame.height)

}
0
ответ дан Sh_Khan 25 August 2018 в 10:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: