Вам необходимо переопределить функцию IAxisValueFormatter
func stringForValue(_ value: Double, axis: AxisBase?) -> String {}
.
Как показано ниже:
Шаг 1: настройте свой xAxis с помощью специального средства форматирования.
let xValues = ["X1", "X2", "X3", "X4", "X5", "X6", "X7", "X8", "X9", "X10"]
let chartFormatter = RadarChartFormatter(labels: xValues)
let xAxis = XAxis()
xAxis.valueFormatter = chartFormatter
self.xAxis.valueFormatter = xAxis.valueFormatter
Шаг 2: Реализация пользовательского форматера с использованием метода ниже.
private class RadarChartFormatter: NSObject, IAxisValueFormatter {
var labels: [String] = []
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
if Int(value) < labels.count {
return labels[Int(value)]
}else{
return String("")
}
}
init(labels: [String]) {
super.init()
self.labels = labels
}
}
Вы получите ниже вывод в вашем RadarCharView:
Надеюсь, это поможет вам получить ваши пользовательские метки на Радиолокационная карта!
Если у вас есть доступ к действию
исходный код, вставьте блок try / catch в этот метод; в противном случае создайте новый метод tryAction
, который обернет вызов действия action
в блок try / catch.
Вы можете добавить try / catch следующим образом:
ThreadPool.QueueUserWorkItem(state =>
{
try
{
action();
}
catch (Exception ex)
{
OnException(ex);
}
});
В другом потоке (в методе, который вы «ставите в очередь», добавьте предложение try catch ... Затем в перехвате поместите перехваченное исключение в общую переменную Exception (видимую для основного потока).
Затем в вашем основном потоке, когда все элементы в очереди закончатся (используйте для этого массив дескрипторов ожидания). поток заполнил это общее исключение исключением ... Если это так, перебросьте его или обработайте соответствующим образом ...
вот пример кода из недавнего проекта, для которого я использовал это ...
HasException является общим логическим значением ...
private void CompleteAndQueuePayLoads(
IEnumerable<UsagePayload> payLoads, string processId)
{
List<WaitHandle> waitHndls = new List<WaitHandle>();
int defaultMaxwrkrThreads, defaultmaxIOThreads;
ThreadPool.GetMaxThreads(out defaultMaxwrkrThreads,
out defaultmaxIOThreads);
ThreadPool.SetMaxThreads(
MDMImportConfig.MAXCONCURRENTIEEUSAGEREQUESTS,
defaultmaxIOThreads);
int qryNo = 0;
foreach (UsagePayload uPL in payLoads)
{
ManualResetEvent txEvnt = new ManualResetEvent(false);
UsagePayload uPL1 = uPL;
int qryNo1 = ++qryNo;
ThreadPool.QueueUserWorkItem(
delegate
{
try
{
Thread.CurrentThread.Name = processId +
"." + qryNo1;
if (!HasException && !uPL1.IsComplete)
IEEDAL.GetPayloadReadings(uPL1,
processId, qryNo1);
if (!HasException)
UsageCache.PersistPayload(uPL1);
if (!HasException)
SavePayLoadToProcessQueueFolder(
uPL1, processId, qryNo1);
}
catch (MeterUsageImportException iX)
{
log.Write(log.Level.Error,
"Delegate failed " iX.Message, iX);
lock (locker)
{
HasException = true;
X = iX;
foreach (ManualResetEvent
txEvt in waitHndls)
txEvt.Set();
}
}
finally { lock(locker) txEvnt.Set(); }
});
waitHndls.Add(txEvnt);
}
util.WaitAll(waitHndls.ToArray());
ThreadPool.SetMaxThreads(defaultMaxwrkrThreads,
defaultmaxIOThreads);
lock (locker) if (X != null) throw X;
}
Обычно я создаю большой блок try ... catch внутри метода action () затем сохраните исключение как частную переменную и обработайте его в основном потоке