我知道这个问题在这个网站上经常被问到,但是我看过的每个问题都有不同的答案,并且我已经尝试了每个问题。
我有一个放置在情节提要中的UIButton,并将其连接到视图控制器中的@IBAction。每次单击按钮时,都会显示错误-[UIViewController openAlert]: unrecognized selector sent to instance
该函数没有参数(我尝试过使用sender参数,它调用openAlertWithSender
而不是openAlert(sender:)
),我发现将按钮连接到类顶部的变量将可以工作,但这给了我一个新错误:This class is not key value coding-compliant
我确保按钮已正确连接到情节提要中的功能,并且确保在视图中启用了用户交互。
我尝试以编程方式构建按钮,但它根本不会出现在屏幕上。
无论我做什么,我似乎都无法使此按钮正常工作。
我的代码:
class OfflineViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Hide the navigation bar
navigationController?.setNavigationBarHidden(true, animated: animated)
NetworkHandler.shared.addListener(listener: self)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Show the navigation bar
navigationController?.setNavigationBarHidden(false, animated: animated)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
NetworkHandler.shared.removeListener(listener: self)
}
private func showMainController() -> Void {
DispatchQueue.main.async {
self.performSegue(withIdentifier: "NetworkAvailable", sender: self)
}
}
@IBAction func openAlert() {
let alert = UIAlertController(title: "Clicked", message: "You have clicked on the button", preferredStyle: .alert)
self.present(alert, animated: true, completion: nil)
}
}
感谢您的帮助。
答案 0 :(得分:0)
首先请确保您已将IB中的类名称分配给vc public class DevicesListFragment extends Fragment implements RecyclerItemTouchHelper.RecyclerItemTouchHelperListener {
private List<Device> deviceList = new ArrayList<>();
private RecyclerView recyclerView;
private DevicesAdapter mAdapter;
private RelativeLayout relativeLayout;
private int buttonR_ID;
private SwipeRefreshLayout swipe;
EditText SETnameDevice, SETnameDivision;
FloatingActionButton addDevice;
EditText nameDevice;
EditText nameDivision;
Switch switchOnOffDevice;
Spinner spTipoDevice;
Spinner spTipoDivision;
Device device;
static ArrayList<Device> devices = new ArrayList<>();
DataCommunicationHome mCallback;
public DevicesListFragment() {
this.buttonR_ID = buttonR_ID;
// Required empty public constructor
}
public void setID(int buttonR_ID) {
this.buttonR_ID = buttonR_ID;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_devices_list, container, false);
setHasOptionsMenu(true);//Make sure you have this line of code.
recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
relativeLayout = (RelativeLayout) view.findViewById(R.id.relative_layout);
deviceList = new ArrayList<>();
mAdapter = new DevicesAdapter(getContext(), deviceList);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(mAdapter);
swipe = view.findViewById(R.id.swiperefresh);
swipe.setColorSchemeResources(R.color.colorAccent, R.color.darkGrey);
swipe.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refresh();
}
});
// adding item touch helper
// only ItemTouchHelper.LEFT added to detect Right to Left swipe
// if you want both Right -> Left and Left -> Right
// add pass ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT as param
ItemTouchHelper.SimpleCallback itemTouchHelperCallback = new RecyclerItemTouchHelper(0, ItemTouchHelper.LEFT,this );
new ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(recyclerView);
prepareDeviceData();
/************************** FLOATING BUTTON **************************************************/
addDevice = view.findViewById(R.id.add_device_buttom);
addDevice.setOnClickListener( new Button.OnClickListener() {
@Override public void onClick(View view) {
AlertDialog.Builder mBuilder = new AlertDialog.Builder(getContext());
final View viewDialog = getLayoutInflater().inflate(R.layout.dialog_add_device, null);
nameDevice = (EditText) viewDialog.findViewById(R.id.name_device);
switchOnOffDevice = (Switch) viewDialog.findViewById(R.id.switch_dialog);
nameDivision = (EditText) viewDialog.findViewById(R.id.name_division);
//########################### Spinner categorias devices #######################################
spTipoDevice = (Spinner) viewDialog.findViewById(R.id.spinnerTipoDevice);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(), android.R.layout.simple_spinner_item, getResources().getStringArray(R.array.device_cat_items));
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spTipoDevice.setAdapter(adapter);
//########################### Spinner categorias Divisions #######################################
spTipoDivision = (Spinner) viewDialog.findViewById(R.id.spinnerDivisao);
ArrayAdapter<String> adapter2 = new ArrayAdapter<String>(getContext(), android.R.layout.simple_spinner_item, getResources().getStringArray(R.array.divisions_cat_items));
adapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spTipoDivision.setAdapter(adapter2);
// ################################## BUTTONS ########################################################
mBuilder.setPositiveButton("CREATE", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int which) {
String deviceSTR = nameDevice.getText().toString();
String divisionSTR = nameDivision.getText().toString();
String deviceCat = spTipoDevice.getSelectedItem().toString();
String divisionCat = spTipoDivision.getSelectedItem().toString();
int onoff;
if (switchOnOffDevice.isChecked()) onoff = 1;
else onoff = 0;
if (!deviceSTR.isEmpty() && !divisionSTR.isEmpty() && !deviceCat.equalsIgnoreCase("Choose a device type...") && !divisionCat.equalsIgnoreCase("Choose a division type...")) {
Toast.makeText(getContext(), "Device created", Toast.LENGTH_SHORT).show();
device = new Device(deviceSTR, onoff, deviceCat, divisionSTR, divisionCat);
devices.add(device);
mCallback.setArrayListDevices(devices);
dialogInterface.dismiss();
} else {
Toast.makeText(getContext(), "Device not created", Toast.LENGTH_SHORT).show();
dialogInterface.dismiss();
}
}
});
mBuilder.setNegativeButton("EXIT", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int which) {
dialogInterface.dismiss();
}
});
mBuilder.setView(viewDialog);
AlertDialog dialog = mBuilder.create();
dialog.show();
dialog.getButton(DialogInterface.BUTTON_NEGATIVE).setTextColor(Color.RED);
}
});
/************************** END Floating Button **************************************************/
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getContext(), recyclerView, new RecyclerTouchListener.ClickListener() {
@Override
public void onClick(View view, int position) {
Device device = deviceList.get(position);
if(device.getOnOff() == 1) {
device.setOnOff(0);
mAdapter.notifyDataSetChanged();
} else if(device.getOnOff() == 0) {
device.setOnOff(1);
mAdapter.notifyDataSetChanged();
}
}
@Override
public void onLongClick(View view, final int position) {
AlertDialog.Builder mBuilder = new AlertDialog.Builder(getContext());
final View viewDialog = getLayoutInflater().inflate(R.layout.dialog_change_device_info, null);
SETnameDevice = (EditText) viewDialog.findViewById(R.id.name_device_change);
SETnameDivision = (EditText) viewDialog.findViewById(R.id.name_division_change);
mBuilder.setPositiveButton("CHANGE", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int which) {
String deviceSTR = SETnameDevice.getText().toString();
String divisionSTR = SETnameDivision.getText().toString();
if (!deviceSTR.isEmpty()) {
deviceList.get(position).setNameDevice(deviceSTR);
mCallback.setArrayListDevices(devices);
mAdapter.notifyDataSetChanged();
Toast.makeText(getContext(), "Device changed", Toast.LENGTH_SHORT).show();
dialogInterface.dismiss();
}
if(!divisionSTR.isEmpty()) {
deviceList.get(position).setNameDivision(divisionSTR);
mCallback.setArrayListDevices(devices);
mAdapter.notifyDataSetChanged();
Toast.makeText(getContext(), "Device changed", Toast.LENGTH_SHORT).show();
dialogInterface.dismiss();
}
}
});
mBuilder.setNegativeButton("EXIT", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int which) {
dialogInterface.dismiss();
}
});
mBuilder.setView(viewDialog);
AlertDialog dialog = mBuilder.create();
dialog.show();
dialog.getButton(DialogInterface.BUTTON_NEGATIVE).setTextColor(Color.RED);
}
}));
return view;
}
private void prepareDeviceData() {
if (deviceList.size() > 0) {
for (int i = 0; i < deviceList.size(); i++) {
deviceList.remove(i);
mAdapter.notifyItemRemoved(i);
}
}
ArrayList<Device> devicesAuxiliar = new ArrayList<Device>();
Device d1 = new Device("Radiator", 0, getString(R.string.thermostats_str), "Bucatarie 1", "Bucatarie");
devicesAuxiliar.add(d1);
Device d2 = new Device("Bec", 0, getString(R.string.lights_str), "Gradina", "Gradina");
devicesAuxiliar.add(d2);
Device d3 = new Device("Bec", 0, getString(R.string.lights_str), "Bucatarie 1", "Bucatarie");
devicesAuxiliar.add(d3);
Device d4 = new Device("Bec", 0, getString(R.string.lights_str), "Sufragerie", "Sufragerie");
devicesAuxiliar.add(d4);
Device d5 = new Device("Bec", 0, getString(R.string.lights_str), "Hol", "Hol");
devicesAuxiliar.add(d5);
Device d6 = new Device("Bec", 0, getString(R.string.lights_str), "Garaj", "Garaj");
devicesAuxiliar.add(d6);
Device d7 = new Device("Usa", 0, getString(R.string.doors_st_r), "Gradina", "Gradina");
devicesAuxiliar.add(d7);
Device d8 = new Device("Poarta Masina", 0, getString(R.string.doors_st_r), "Curte", "Curte");
devicesAuxiliar.add(d8);
Device d9 = new Device("Usa", 0, getString(R.string.doors_st_r), "Casa", "Casa");
devicesAuxiliar.add(d9);
if(!mCallback.getArrayListDevices().isEmpty());
devicesAuxiliar.addAll(mCallback.getArrayListDevices());
int BotaoID = mCallback.getIDButtonDevices();
for(Device device : devicesAuxiliar) {
if (BotaoID == R.id.card_smart_lights)
if (device.getDeviceType().equals(getString(R.string.lights_str)))
deviceList.add(device);
if (BotaoID == R.id.card_smart_plugins)
if (device.getDeviceType().equals(getString(R.string.smart_plugin_str)))
deviceList.add(device);
if (BotaoID == R.id.card_thermostats)
if (device.getDeviceType().equals(getString(R.string.thermostats_str)))
deviceList.add(device);
if(BotaoID == R.id.card_Doors)
if(device.getDeviceType().equals(getString(R.string.doors_st_r)))
deviceList.add(device);
if(BotaoID == 0)
if(device.getNameDivision().equalsIgnoreCase(mCallback.getArrayListDevices().get(0).getNameDivision()))
deviceList.add(device);
}
mAdapter.notifyDataSetChanged();
}
public void refresh() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (deviceList.size() > 0) {
for (int i = 0; i < deviceList.size(); i++) {
deviceList.remove(i);
mAdapter.notifyItemRemoved(i);
}
}
prepareDeviceData();
swipe.setRefreshing(false);
//ola.
// ola2
// ola 3
// ola 4.
}
}, 1000);
}
/**
* callback when recycler view is swiped
* item will be removed on swiped
* undo option will be provided in snackbar to restore the item
*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position) {
if (viewHolder instanceof DevicesAdapter.MyViewHolder) {
// get the removed item name to display it in snack bar
String name = deviceList.get(viewHolder.getAdapterPosition()).getNameDevice();
// backup of removed item for undo purpose
final Device deletedItem = deviceList.get(viewHolder.getAdapterPosition());
final int deletedIndex = viewHolder.getAdapterPosition();
// remove the item from recycler view
mAdapter.removeItem(viewHolder.getAdapterPosition());
// showing snack bar with Undo option
Snackbar snackbar = Snackbar
.make(relativeLayout, name + " removed from cart!", Snackbar.LENGTH_LONG);
snackbar.setAction("UNDO", new View.OnClickListener() {
@Override
public void onClick(View view) {
// undo is selected, restore the deleted item
mAdapter.restoreItem(deletedItem, deletedIndex);
}
});
View view = snackbar.getView();
CoordinatorLayout.LayoutParams params =(CoordinatorLayout.LayoutParams)view.getLayoutParams();
params.gravity = Gravity.TOP;
view.setLayoutParams(params);
snackbar.setActionTextColor(Color.YELLOW);
snackbar.show();
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
devicesAuxiliar.add
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (DataCommunicationHome) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement DataCommunication");
}
}
public void showDevicesListFragment(int rID)
{
mCallback.setIDButtonDevices(rID);
Fragment fr = new DevicesListFragment();
FragmentChangeListener fc=(FragmentChangeListener)getActivity();
fc.replaceFragment(fr);
}
第二个添加此方法
OfflineViewController
似乎您在将其命名为@IBAction func printMessage(_ sender:UIButton) { }
之后更改了它的名称,而不是openAlert
,并且IB封装了不再存在的旧名称,因此崩溃了
注意:情节提要是幕后的xml文件,因此每个插口名称/动作名称都会保留,直到您对其进行更改为止,并且没有错误机制可以告诉您何时编译