Math.sum (javascript) .... вид замещения оператора
.1 + .0001 + -.1 --> 0.00010000000000000286
Math.sum(.1 , .0001, -.1) --> 0.0001
Object.defineProperties(Math, {
sign: {
value: function (x) {
return x ? x < 0 ? -1 : 1 : 0;
}
},
precision: {
value: function (value, precision, type) {
var v = parseFloat(value),
p = Math.max(precision, 0) || 0,
t = type || 'round';
return (Math[t](v * Math.pow(10, p)) / Math.pow(10, p)).toFixed(p);
}
},
scientific_to_num: { // this is from https://gist.github.com/jiggzson
value: function (num) {
//if the number is in scientific notation remove it
if (/e/i.test(num)) {
var zero = '0',
parts = String(num).toLowerCase().split('e'), //split into coeff and exponent
e = parts.pop(), //store the exponential part
l = Math.abs(e), //get the number of zeros
sign = e / l,
coeff_array = parts[0].split('.');
if (sign === -1) {
num = zero + '.' + new Array(l).join(zero) + coeff_array.join('');
} else {
var dec = coeff_array[1];
if (dec)
l = l - dec.length;
num = coeff_array.join('') + new Array(l + 1).join(zero);
}
}
return num;
}
}
get_precision: {
value: function (number) {
var arr = Math.scientific_to_num((number + "")).split(".");
return arr[1] ? arr[1].length : 0;
}
},
diff:{
value: function(A,B){
var prec = this.max(this.get_precision(A),this.get_precision(B));
return +this.precision(A-B,prec);
}
},
sum: {
value: function () {
var prec = 0, sum = 0;
for (var i = 0; i < arguments.length; i++) {
prec = this.max(prec, this.get_precision(arguments[i]));
sum += +arguments[i]; // force float to convert strings to number
}
return Math.precision(sum, prec);
}
}
});
Идея состоит в том, чтобы вместо Math вместо Math использовать ошибки плавания
Math.diff(0.2, 0.11) == 0.09 // true
0.2 - 0.11 == 0.09 // false
также отмечают, что Math.diff и Math.sum автоматически определяют точность использования
. Math.sum принимает любое количество аргументов
Как отметил @nhgrif в своем превосходном ответе, существует множество способов, которыми VC (контроллеры просмотра) и другие объекты могут связываться друг с другом.
Синтаксис данных, который я изложил в своем первом ответе действительно больше касается обмена и сохранения глобального состояния, чем непосредственного общения.
Ответ nhrif позволяет отправлять информацию непосредственно из источника в пункт назначения VC. Как я уже упоминал в ответ, также можно отправлять сообщения от адресата к источнику.
Фактически вы можете настроить активный односторонний или двухсторонний канал между различными контроллерами. Если контроллеры представлений связаны через segue раскадровки, время, необходимое для настройки ссылок, находится в методе prepareFor Segue.
У меня есть пример проекта в Github, который использует родительский контроллер представления для размещения 2 разных таблиц как дети. Контроллеры дочерних представлений связаны с использованием встроенных сегментов, а контроллер родительского представления подключает двухсторонние ссылки с каждым контроллером представления в методе prepareForSegue.
Вы можете найти этот проект на github (ссылка). Однако я написал его в Objective-C и не преобразовал его в Swift, поэтому, если вам не удобно в Objective-C, может быть немного трудно следовать
Swift 4
Существует так много подходов к передаче данных в swift. Здесь я добавляю некоторые из лучших подходов к нему.
1) Использование StoryBoard Segue
Сетчатые раскладки очень полезны для передачи данных между контроллерами Source и Destination View Controllers и наоборот также.
// If you want to pass data from ViewControllerB to ViewControllerA while user tap on back button of ViewControllerB.
@IBAction func unWindSeague (_ sender : UIStoryboardSegue) {
if sender.source is ViewControllerB {
if let _ = sender.source as? ViewControllerB {
self.textLabel.text = "Came from B = B->A , B exited"
}
}
}
// If you want to send data from ViewControllerA to ViewControllerB
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.destination is ViewControllerB {
if let vc = segue.destination as? ViewControllerB {
vc.dataStr = "Comming from A View Controller"
}
}
}
2) Использование методов делегата
ViewControllerD
//Make the Delegate protocol in Child View Controller (Make the protocol in Class from You want to Send Data)
protocol SendDataFromDelegate {
func sendData(data : String)
}
import UIKit
class ViewControllerD: UIViewController {
@IBOutlet weak var textLabelD: UILabel!
var delegate : SendDataFromDelegate? //Create Delegate Variable for Registering it to pass the data
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
textLabelD.text = "Child View Controller"
}
@IBAction func btnDismissTapped (_ sender : UIButton) {
textLabelD.text = "Data Sent Successfully to View Controller C using Delegate Approach"
self.delegate?.sendData(data:textLabelD.text! )
_ = self.dismiss(animated: true, completion:nil)
}
}
ViewControllerC
import UIKit
class ViewControllerC: UIViewController , SendDataFromDelegate {
@IBOutlet weak var textLabelC: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBAction func btnPushToViewControllerDTapped( _ sender : UIButton) {
if let vcD = self.storyboard?.instantiateViewController(withIdentifier: "ViewControllerD") as? ViewControllerD {
vcD.delegate = self // Registring Delegate (When View Conteoller D gets Dismiss It can call sendData method
// vcD.textLabelD.text = "This is Data Passing by Referenceing View Controller D Text Label." //Data Passing Between View Controllers using Data Passing
self.present(vcD, animated: true, completion: nil)
}
}
//This Method will called when when viewcontrollerD will dismiss. (You can also say it is a implementation of Protocol Method)
func sendData(data: String) {
self.textLabelC.text = data
}
}
Вместо создания контроллера данных контроллера я бы предложил создать экземпляр контроллера данных и передать его. Чтобы поддерживать инъекцию зависимостей, я бы сначала создал протокол DataController
:
protocol DataController {
var someInt : Int {get set}
var someString : String {get set}
}
Тогда я бы создал SpecificDataController
(или любое другое имя в настоящее время было бы подходящим) class:
class SpecificDataController : DataController {
var someInt : Int = 5
var someString : String = "Hello data"
}
Класс ViewController
должен иметь поле для удерживания dataController
. Обратите внимание, что тип dataController
- это протокол DataController
. Таким образом, легко отключить реализации контроллера данных:
class ViewController : UIViewController {
var dataController : DataController?
...
}
В AppDelegate
мы можем установить viewController dataController
:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if let viewController = self.window?.rootViewController as? ViewController {
viewController.dataController = SpecificDataController()
}
return true
}
. Когда мы переходим к другому viewController мы можем передать dataController
в:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
...
}
Теперь, когда мы хотим отключить контроллер данных для другой задачи, мы можем сделать это в AppDelegate
и не нужно менять любой другой код, который использует контроллер данных.
Это, конечно, излишне, если мы просто хотим передать одно значение. В этом случае лучше всего пойти с ответом nhgrif.
При таком подходе мы можем разделить вид логической части.
SWIFT 3:
Если у вас есть раскадровка с идентифицированными выделениями, используйте:
func prepare(for segue: UIStoryboardSegue, sender: Any?)
Хотя, если вы все программно осуществляете навигацию между различными UIViewControllers, используйте метод:
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool)
Примечание: чтобы использовать второй способ, которым вам нужен ваш UINavigationController, вы нажимаете UIViewControllers на, делегат, и он должен соответствовать протоколу UINavigationControllerDelegate:
class MyNavigationController: UINavigationController, UINavigationControllerDelegate {
override func viewDidLoad() {
self.delegate = self
}
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
// do what ever you need before going to the next UIViewController or back
//this method will be always called when you are pushing or popping the ViewController
}
}
Ваш вопрос very wide. Предложить, что есть одно простое решение для каждого сценария, немного наивное. Итак, давайте рассмотрим некоторые из этих сценариев.
Самый распространенный сценарий, о котором я спрашивал о переполнении стека в своем опыте, - это простая передача информации с одного контроллера вида на следующий.
Если мы используем раскадровку, наш первый контроллер представления может переопределить prepareForSegue
, что и есть то, для чего оно предназначено. Объект UIStoryboardSegue
передается при вызове этого метода и содержит ссылку на наш контроллер представления назначения. Здесь мы можем установить значения, которые мы хотим передать.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "MySegueID" {
if let destination = segue.destinationViewController as? SecondController {
destination.myInformation = self.myInformation
}
}
}
В качестве альтернативы, если мы не используем раскадровки, мы загружаем наш контроллер представлений из наконечника. Наш код немного проще.
func showNextController() {
let destination = SecondController(nibName: "SecondController", bundle: NSBundle.mainBundle())
destination.myInformation = self.myInformation
self.showViewController(destination, sender: self)
}
В обоих случаях myInformation
является свойством на каждом контроллере представления, в котором все данные должны передаваться с одного контроллера представления на следующий. Очевидно, что они не должны иметь одно и то же имя на каждом контроллере.
Мы также можем поделиться информацией между вкладками в UITabBarController
.
В этом случае , это на самом деле потенциально даже проще.
Сначала создадим подкласс UITabBarController
и дадим ему свойства для любой информации, которую мы хотим разделить между различными вкладками:
class MyCustomTabController: UITabBarController {
var myInformation: [String: AnyObject]?
}
Теперь, если мы создавая наше приложение из раскадровки, мы просто меняем класс контроллера панели вкладок от значения по умолчанию UITabBarController
до MyCustomTabController
. Если мы не используем раскадровку, мы просто создаем экземпляр этого пользовательского класса, а не класс по умолчанию UITabBarController
, и добавим к этому наш контроллер.
Теперь все наши контроллеры представлений в контроллер панели вкладок может получить доступ к этому свойству как таковому:
if let tbc = self.tabBarController as? MyCustomTabController {
// do something with tbc.myInformation
}
И таким же образом путем подкласса UINavigationController
мы можем использовать тот же подход для совместного использования данных по всему стеку навигации:
if let nc = self.navigationController as? MyCustomNavController {
// do something with nc.myInformation
}
Существует несколько других сценариев. Ни в коем случае этот ответ не охватывает всех из них.