[Cocoa]_[初级]_[使用NSNotificationCenter作为目标观察者实现时需要注意的事项]
场景
- 在开发
Cocoa程序时,由于界面是用Objective-C写的。无法使用C++的目标观察者[1]类。如果是使用第二种方案2[2],那么也需要增加一个代理类。那么有没有更省事的办法?
说明
-
开发界面的时候,经常是需要在子界面里传递数据给主界面,主界面获得数据后跟业务逻辑交互。目前子界面和主界面的数据交互目前使用发布订阅(观察者模式)的设计模式是比较好的,因为它可以让两个界面解耦合。
-
之前说过在
Cocoa程序里,可以使用NSNotificationCenter通知中心发布接收消息注意事项来作为消息传递的观察者实现。这里要强调一个问题,就是NSNotificationCenter注册的观察者必须要设置接收对象,也就是以下的object参数。如果参数设置为nil,当有多个地方注册同样的观察者时,目标如果发送MyNotificationChangeBackgroundColor消息,所有的观察者都有接收到这个消息,会导致该消息执行多次。特别是以下代码self对象是多个实例时。
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(recvNotificationMessage:) name:@(MyNotificationChangeBackgroundColor) object:subject];
- 发送
MyNotificationChangeBackgroundColor消息, 注意要指定object参数值。
-(IBAction)onChange:(id)sender
{static int mod = 1;if(mod++ % 2){NSColor* color = [NSColor colorWithSRGBRed:255/255.0 green:255/255.0 blue:255/255.0 alpha:1];[[NSNotificationCenter defaultCenter] postNotificationName:@(MyNotificationChangeBackgroundColor) object:self userInfo:@{@"color":color}];}else{NSColor* color = [NSColor colorWithSRGBRed:240/255.0 green:122/255.0 blue:55/255.0 alpha:1];[[NSNotificationCenter defaultCenter] postNotificationName:@(MyNotificationChangeBackgroundColor) object:view1_ userInfo:@{@"color":color}];}}
例子
- 以下例子说明如何创建响应指定目标的观察者。点击两次
Change按钮会依次更改子视图1和2的背景色,而它们发送的是同样的消息。
AppDelegate.h
#import <Cocoa/Cocoa.h>
#import "MyView.h"@interface AppDelegate : NSObject <NSApplicationDelegate>
{IBOutlet MyView* view1_;IBOutlet MyView* view2_;
}-(IBAction)onChange:(id)sender;-(IBAction)onReset:(id)sender;@end
AppDelegate.mm
#import "AppDelegate.h"
#include "platform.h"@interface AppDelegate ()@property (weak) IBOutlet NSWindow *window;
@end@implementation AppDelegate-(void)changeBackgroundColor:(NSView*)view withColor:(NSColor*)color1
{[view setWantsLayer:YES];CGColorSpaceRef space = [[color1 colorSpace] CGColorSpace];CGFloat components[] ={color1.redComponent,color1.greenComponent,color1.blueComponent,color1.alphaComponent};CGColorRef color_ref = CGColorCreate(space,components);[[view layer] setBackgroundColor:color_ref];CGColorRelease(color_ref);
}- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {// Insert code here to initialize your application[self onReset:nil];[view1_ registerObserver:self]; // 只接收来自self的消息[view2_ registerObserver:view1_]; // 只接收来自view1的消息
}- (void)applicationWillTerminate:(NSNotification *)aNotification {// Insert code here to tear down your application
}-(IBAction)onChange:(id)sender
{static int mod = 1;if(mod++ % 2){NSColor* color = [NSColor colorWithSRGBRed:255/255.0 green:255/255.0 blue:255/255.0 alpha:1];[[NSNotificationCenter defaultCenter] postNotificationName:@(MyNotificationChangeBackgroundColor) object:self userInfo:@{@"color":color}];}else{NSColor* color = [NSColor colorWithSRGBRed:240/255.0 green:122/255.0 blue:55/255.0 alpha:1];[[NSNotificationCenter defaultCenter] postNotificationName:@(MyNotificationChangeBackgroundColor) object:view1_ userInfo:@{@"color":color}];}}-(IBAction)onReset:(id)sender
{[self changeBackgroundColor:view1_ withColor:[NSColor redColor]];[self changeBackgroundColor:view2_ withColor:[NSColor blueColor]];
}@end
MyView.h
#import <Cocoa/Cocoa.h>NS_ASSUME_NONNULL_BEGIN@interface MyView : NSView-(void)registerObserver:(id __nullable)subject;-(void)removeObserver:(id)subject;@endNS_ASSUME_NONNULL_END
MyView.mm
#import "MyView.h"
#include "platform.h"@implementation MyView- (void)drawRect:(NSRect)dirtyRect {[super drawRect:dirtyRect];// Drawing code here.
}-(void)changeBackgroundColor:(NSView*)view withColor:(NSColor*)color1
{[view setWantsLayer:YES];CGColorSpaceRef space = [[color1 colorSpace] CGColorSpace];CGFloat components[] ={color1.redComponent,color1.greenComponent,color1.blueComponent,color1.alphaComponent};CGColorRef color_ref = CGColorCreate(space,components);[[view layer] setBackgroundColor:color_ref];CGColorRelease(color_ref);
}-(void)recvNotificationMessage:(NSNotification*) notification
{if([notification.name compare:@(MyNotificationChangeBackgroundColor)] == NSOrderedSame){NSDictionary* dict = notification.userInfo;NSColor* color = [dict objectForKey:@"color"];[self changeBackgroundColor:self withColor:color];}
}-(void)registerObserver:(id)subject
{[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(recvNotificationMessage:) name:@(MyNotificationChangeBackgroundColor) object:subject];
}-(void)removeObserver:(id)subject
{[[NSNotificationCenter defaultCenter] removeObserver:self name:@(MyNotificationChangeBackgroundColor) object:subject];
}-(void)awakeFromNib
{}@end
platform.h
#ifndef platform_h
#define platform_h#define MyNotificationChangeBackgroundColor "MyNotificationChangeBackgroundColor"#endif /* platform_h */
main.m
#import <Cocoa/Cocoa.h>int main(int argc, const char * argv[]) {return NSApplicationMain(argc, argv);
}
MainMenu.xib
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"><dependencies><plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/><capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/></dependencies><objects><customObject id="-2" userLabel="File's Owner" customClass="NSApplication"><connections><outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/></connections></customObject><customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/><customObject id="-3" userLabel="Application"/><customObject id="Voe-Tx-rLC" customClass="AppDelegate"><connections><outlet property="view1_" destination="Gxg-KB-hXo" id="0fI-03-3v8"/><outlet property="view2_" destination="4YQ-ZK-Q0W" id="4bZ-O9-7Dg"/><outlet property="window" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/></connections></customObject><customObject id="YLy-65-1bz" customClass="NSFontManager"/><menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6"><items><menuItem title="NotificationTest" id="1Xt-HY-uBw"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="NotificationTest" systemMenu="apple" id="uQy-DD-JDr"><items><menuItem title="About NotificationTest" id="5kV-Vb-QxS"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/></connections></menuItem><menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/><menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/><menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/><menuItem title="Services" id="NMo-om-nkz"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/></menuItem><menuItem isSeparatorItem="YES" id="4je-JR-u6R"/><menuItem title="Hide NotificationTest" keyEquivalent="h" id="Olw-nP-bQN"><connections><action selector="hide:" target="-1" id="PnN-Uc-m68"/></connections></menuItem><menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO"><modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/><connections><action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/></connections></menuItem><menuItem title="Show All" id="Kd2-mp-pUS"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/></connections></menuItem><menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/><menuItem title="Quit NotificationTest" keyEquivalent="q" id="4sb-4s-VLi"><connections><action selector="terminate:" target="-1" id="Te7-pn-YzF"/></connections></menuItem></items></menu></menuItem><menuItem title="File" id="dMs-cI-mzQ"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="File" id="bib-Uj-vzu"><items><menuItem title="New" keyEquivalent="n" id="Was-JA-tGl"><connections><action selector="newDocument:" target="-1" id="4Si-XN-c54"/></connections></menuItem><menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9"><connections><action selector="openDocument:" target="-1" id="bVn-NM-KNZ"/></connections></menuItem><menuItem title="Open Recent" id="tXI-mr-wws"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ"><items><menuItem title="Clear Menu" id="vNY-rz-j42"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="clearRecentDocuments:" target="-1" id="Daa-9d-B3U"/></connections></menuItem></items></menu></menuItem><menuItem isSeparatorItem="YES" id="m54-Is-iLE"/><menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG"><connections><action selector="performClose:" target="-1" id="HmO-Ls-i7Q"/></connections></menuItem><menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV"><connections><action selector="saveDocument:" target="-1" id="teZ-XB-qJY"/></connections></menuItem><menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A"><connections><action selector="saveDocumentAs:" target="-1" id="mDf-zr-I0C"/></connections></menuItem><menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H"><connections><action selector="revertDocumentToSaved:" target="-1" id="iJ3-Pv-kwq"/></connections></menuItem><menuItem isSeparatorItem="YES" id="aJh-i4-bef"/><menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK"><modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/><connections><action selector="runPageLayout:" target="-1" id="Din-rz-gC5"/></connections></menuItem><menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS"><connections><action selector="print:" target="-1" id="qaZ-4w-aoO"/></connections></menuItem></items></menu></menuItem><menuItem title="Edit" id="5QF-Oa-p0T"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Edit" id="W48-6f-4Dl"><items><menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg"><connections><action selector="undo:" target="-1" id="M6e-cu-g7V"/></connections></menuItem><menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam"><connections><action selector="redo:" target="-1" id="oIA-Rs-6OD"/></connections></menuItem><menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/><menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG"><connections><action selector="cut:" target="-1" id="YJe-68-I9s"/></connections></menuItem><menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU"><connections><action selector="copy:" target="-1" id="G1f-GL-Joy"/></connections></menuItem><menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL"><connections><action selector="paste:" target="-1" id="UvS-8e-Qdg"/></connections></menuItem><menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk"><modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/><connections><action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/></connections></menuItem><menuItem title="Delete" id="pa3-QI-u2k"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="delete:" target="-1" id="0Mk-Ml-PaM"/></connections></menuItem><menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m"><connections><action selector="selectAll:" target="-1" id="VNm-Mi-diN"/></connections></menuItem><menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/><menuItem title="Find" id="4EN-yA-p0u"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Find" id="1b7-l0-nxx"><items><menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W"><connections><action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/></connections></menuItem><menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz"><modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/><connections><action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/></connections></menuItem><menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye"><connections><action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/></connections></menuItem><menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV"><connections><action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/></connections></menuItem><menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt"><connections><action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/></connections></menuItem><menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd"><connections><action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/></connections></menuItem></items></menu></menuItem><menuItem title="Spelling and Grammar" id="Dv1-io-Yv7"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Spelling" id="3IN-sU-3Bg"><items><menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI"><connections><action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/></connections></menuItem><menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7"><connections><action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/></connections></menuItem><menuItem isSeparatorItem="YES" id="bNw-od-mp5"/><menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/></connections></menuItem><menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/></connections></menuItem><menuItem title="Correct Spelling Automatically" id="78Y-hA-62v"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/></connections></menuItem></items></menu></menuItem><menuItem title="Substitutions" id="9ic-FL-obx"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Substitutions" id="FeM-D8-WVr"><items><menuItem title="Show Substitutions" id="z6F-FW-3nz"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/></connections></menuItem><menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/><menuItem title="Smart Copy/Paste" id="9yt-4B-nSM"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/></connections></menuItem><menuItem title="Smart Quotes" id="hQb-2v-fYv"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/></connections></menuItem><menuItem title="Smart Dashes" id="rgM-f4-ycn"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/></connections></menuItem><menuItem title="Smart Links" id="cwL-P1-jid"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/></connections></menuItem><menuItem title="Data Detectors" id="tRr-pd-1PS"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/></connections></menuItem><menuItem title="Text Replacement" id="HFQ-gK-NFA"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/></connections></menuItem></items></menu></menuItem><menuItem title="Transformations" id="2oI-Rn-ZJC"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Transformations" id="c8a-y6-VQd"><items><menuItem title="Make Upper Case" id="vmV-6d-7jI"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/></connections></menuItem><menuItem title="Make Lower Case" id="d9M-CD-aMd"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/></connections></menuItem><menuItem title="Capitalize" id="UEZ-Bs-lqG"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/></connections></menuItem></items></menu></menuItem><menuItem title="Speech" id="xrE-MZ-jX0"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Speech" id="3rS-ZA-NoH"><items><menuItem title="Start Speaking" id="Ynk-f8-cLZ"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/></connections></menuItem><menuItem title="Stop Speaking" id="Oyz-dy-DGm"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/></connections></menuItem></items></menu></menuItem></items></menu></menuItem><menuItem title="Format" id="jxT-CU-nIS"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Format" id="GEO-Iw-cKr"><items><menuItem title="Font" id="Gi5-1S-RQB"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq"><items><menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq"><connections><action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/></connections></menuItem><menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27"><connections><action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/></connections></menuItem><menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq"><connections><action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/></connections></menuItem><menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S"><connections><action selector="underline:" target="-1" id="FYS-2b-JAY"/></connections></menuItem><menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/><menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL"><connections><action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/></connections></menuItem><menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST"><connections><action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/></connections></menuItem><menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/><menuItem title="Kern" id="jBQ-r6-VK2"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Kern" id="tlD-Oa-oAM"><items><menuItem title="Use Default" id="GUa-eO-cwY"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="useStandardKerning:" target="-1" id="6dk-9l-Ckg"/></connections></menuItem><menuItem title="Use None" id="cDB-IK-hbR"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="turnOffKerning:" target="-1" id="U8a-gz-Maa"/></connections></menuItem><menuItem title="Tighten" id="46P-cB-AYj"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="tightenKerning:" target="-1" id="hr7-Nz-8ro"/></connections></menuItem><menuItem title="Loosen" id="ogc-rX-tC1"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="loosenKerning:" target="-1" id="8i4-f9-FKE"/></connections></menuItem></items></menu></menuItem><menuItem title="Ligatures" id="o6e-r0-MWq"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Ligatures" id="w0m-vy-SC9"><items><menuItem title="Use Default" id="agt-UL-0e3"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="useStandardLigatures:" target="-1" id="7uR-wd-Dx6"/></connections></menuItem><menuItem title="Use None" id="J7y-lM-qPV"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="turnOffLigatures:" target="-1" id="iX2-gA-Ilz"/></connections></menuItem><menuItem title="Use All" id="xQD-1f-W4t"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="useAllLigatures:" target="-1" id="KcB-kA-TuK"/></connections></menuItem></items></menu></menuItem><menuItem title="Baseline" id="OaQ-X3-Vso"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Baseline" id="ijk-EB-dga"><items><menuItem title="Use Default" id="3Om-Ey-2VK"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="unscript:" target="-1" id="0vZ-95-Ywn"/></connections></menuItem><menuItem title="Superscript" id="Rqc-34-cIF"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="superscript:" target="-1" id="3qV-fo-wpU"/></connections></menuItem><menuItem title="Subscript" id="I0S-gh-46l"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="subscript:" target="-1" id="Q6W-4W-IGz"/></connections></menuItem><menuItem title="Raise" id="2h7-ER-AoG"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="raiseBaseline:" target="-1" id="4sk-31-7Q9"/></connections></menuItem><menuItem title="Lower" id="1tx-W0-xDw"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="lowerBaseline:" target="-1" id="OF1-bc-KW4"/></connections></menuItem></items></menu></menuItem><menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/><menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk"><connections><action selector="orderFrontColorPanel:" target="-1" id="mSX-Xz-DV3"/></connections></menuItem><menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/><menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD"><modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/><connections><action selector="copyFont:" target="-1" id="GJO-xA-L4q"/></connections></menuItem><menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH"><modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/><connections><action selector="pasteFont:" target="-1" id="JfD-CL-leO"/></connections></menuItem></items></menu></menuItem><menuItem title="Text" id="Fal-I4-PZk"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Text" id="d9c-me-L2H"><items><menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1"><connections><action selector="alignLeft:" target="-1" id="zUv-R1-uAa"/></connections></menuItem><menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb"><connections><action selector="alignCenter:" target="-1" id="spX-mk-kcS"/></connections></menuItem><menuItem title="Justify" id="J5U-5w-g23"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="alignJustified:" target="-1" id="ljL-7U-jND"/></connections></menuItem><menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4"><connections><action selector="alignRight:" target="-1" id="r48-bG-YeY"/></connections></menuItem><menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/><menuItem title="Writing Direction" id="H1b-Si-o9J"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd"><items><menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH"><modifierMask key="keyEquivalentModifierMask"/></menuItem><menuItem id="YGs-j5-SAR"><string key="title"> Default</string><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="makeBaseWritingDirectionNatural:" target="-1" id="qtV-5e-UBP"/></connections></menuItem><menuItem id="Lbh-J2-qVU"><string key="title"> Left to Right</string><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="makeBaseWritingDirectionLeftToRight:" target="-1" id="S0X-9S-QSf"/></connections></menuItem><menuItem id="jFq-tB-4Kx"><string key="title"> Right to Left</string><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="makeBaseWritingDirectionRightToLeft:" target="-1" id="5fk-qB-AqJ"/></connections></menuItem><menuItem isSeparatorItem="YES" id="swp-gr-a21"/><menuItem title="Selection" enabled="NO" id="cqv-fj-IhA"><modifierMask key="keyEquivalentModifierMask"/></menuItem><menuItem id="Nop-cj-93Q"><string key="title"> Default</string><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="makeTextWritingDirectionNatural:" target="-1" id="lPI-Se-ZHp"/></connections></menuItem><menuItem id="BgM-ve-c93"><string key="title"> Left to Right</string><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="makeTextWritingDirectionLeftToRight:" target="-1" id="caW-Bv-w94"/></connections></menuItem><menuItem id="RB4-Sm-HuC"><string key="title"> Right to Left</string><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="makeTextWritingDirectionRightToLeft:" target="-1" id="EXD-6r-ZUu"/></connections></menuItem></items></menu></menuItem><menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/><menuItem title="Show Ruler" id="vLm-3I-IUL"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="toggleRuler:" target="-1" id="FOx-HJ-KwY"/></connections></menuItem><menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5"><modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/><connections><action selector="copyRuler:" target="-1" id="71i-fW-3W2"/></connections></menuItem><menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI"><modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/><connections><action selector="pasteRuler:" target="-1" id="cSh-wd-qM2"/></connections></menuItem></items></menu></menuItem></items></menu></menuItem><menuItem title="View" id="H8h-7b-M4v"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="View" id="HyV-fh-RgO"><items><menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5"><modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/><connections><action selector="toggleToolbarShown:" target="-1" id="BXY-wc-z0C"/></connections></menuItem><menuItem title="Customize Toolbar…" id="1UK-8n-QPP"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="runToolbarCustomizationPalette:" target="-1" id="pQI-g3-MTW"/></connections></menuItem><menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/><menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE"><modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/><connections><action selector="toggleSourceList:" target="-1" id="iwa-gc-5KM"/></connections></menuItem><menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa"><modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/><connections><action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/></connections></menuItem></items></menu></menuItem><menuItem title="Window" id="aUF-d1-5bR"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo"><items><menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV"><connections><action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/></connections></menuItem><menuItem title="Zoom" id="R4o-n2-Eq4"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="performZoom:" target="-1" id="DIl-cC-cCs"/></connections></menuItem><menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/><menuItem title="Bring All to Front" id="LE2-aR-0XJ"><modifierMask key="keyEquivalentModifierMask"/><connections><action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/></connections></menuItem></items></menu></menuItem><menuItem title="Help" id="wpr-3q-Mcd"><modifierMask key="keyEquivalentModifierMask"/><menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ"><items><menuItem title="NotificationTest Help" keyEquivalent="?" id="FKE-Sm-Kum"><connections><action selector="showHelp:" target="-1" id="y7X-2Q-9no"/></connections></menuItem></items></menu></menuItem></items></menu><window title="NotificationTest" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g"><windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/><windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/><rect key="contentRect" x="335" y="390" width="480" height="360"/><rect key="screenRect" x="0.0" y="0.0" width="1366" height="745"/><view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ"><rect key="frame" x="0.0" y="0.0" width="480" height="360"/><autoresizingMask key="autoresizingMask"/><subviews><customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Gxg-KB-hXo" customClass="MyView"><rect key="frame" x="31" y="193" width="183" height="124"/><autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/></customView><customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4YQ-ZK-Q0W" customClass="MyView"><rect key="frame" x="257" y="193" width="174" height="124"/><autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/></customView><button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="sbg-pR-7xp"><rect key="frame" x="353" y="13" width="87" height="32"/><autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/><buttonCell key="cell" type="push" title="Change" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="MHb-HO-fqR"><behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/><font key="font" metaFont="system"/></buttonCell><connections><action selector="onChange:" target="Voe-Tx-rLC" id="0CQ-0i-z8w"/></connections></button><button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="FRq-bN-yDD"><rect key="frame" x="273" y="13" width="75" height="32"/><autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/><buttonCell key="cell" type="push" title="Reset" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="JP3-gy-SnJ"><behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/><font key="font" metaFont="system"/></buttonCell><connections><action selector="onReset:" target="Voe-Tx-rLC" id="TtH-x7-6B2"/></connections></button></subviews></view></window></objects>
</document>
例子
图1

参考
1.观察者模式在项目中实际使用例子
2.观察者模式在项目中实际使用例子2
3.NSNotificationCenter通知中心发布接收消息注意事项
相关文章:
[Cocoa]_[初级]_[使用NSNotificationCenter作为目标观察者实现时需要注意的事项]
场景 在开发Cocoa程序时,由于界面是用Objective-C写的。无法使用C的目标观察者[1]类。如果是使用第二种方案2[2],那么也需要增加一个代理类。那么有没有更省事的办法? 说明 开发界面的时候,经常是需要在子界面里传递数据给主界面࿰…...
彩虹易支付最新版源码及安装教程(修复BUG+新增加订单投诉功能)
该源码当前版本为较新的版本,新增了订单投诉功能和一套精美的二次元模板。 此版本为全开源版本,所有文件均未加密。系统默认安装完成后无法直接打开,需要进一步配置。 本站特别针对BUG文件进行了修复,且在PHP7.4环境下表现良好。…...
ping香港服务器超时的原因通常有哪些?
Ping命令用于测试计算机与目标服务器之间的网络连接。当您在尝试使用ping命令检测服务器时遇到超时的情况,通常可能是由以下原因造成的: 1. 网络连接问题: - 本地网络故障:如网线损坏、路由器故障或配置不当。 - ISP(互联网服务提…...
书生大模型实战(从入门到进阶)L3-彩蛋岛-InternLM 1.8B 模型 Android 端侧部署实践
目录 1 环境准备 1.1 安装rust 1.2 安装Android Studio 1.3 设置环境变量 2 转换模型 2.1 安装mlc-llm 2.2 (可选)转换参数 2.3 (可选)生成配置 2.4 (可选)上传到huggingface 2.5 (可选) 测试转换的模型 3 打包运行 3.1 修改配置文件 3.2 运行打包命令 3.3 创建签…...
setState是同步更新还是异步更新
setState是同步更新还是异步更新 先说结论setState为什么设计为异步react18之前为什么不确定是同步还是异步呢react18之后setState有哪些改动 先说结论 React18之前:使用了ReactDOM.render,setState在React调度流程中是异步更新,在原生事件和…...
TCP 流量控制 - 滑动窗口和拥塞控制算法解析
滑动窗口主要管理数据流动的速率,对单个连接较好,拥塞控制则防止网络出现过载,对提高整体的网络通畅较好。下面详细解析两者的原理和作用。 1. TCP 滑动窗口算法 TCP 使用滑动窗口机制来控制数据的发送和接收,以实现流量控制&…...
MongoDB聚合操作及索引底层原理
目录 链接:https://note.youdao.com/ynoteshare/index.html?id=50fdb657a9b06950fa255a82555b44a6&type=note&_time=1727951783296 本节课的内容: 聚合操作: 聚合管道操作: 编辑 $match 进行文档筛选 编辑 将筛选和投影结合使用: 编辑 多条件匹配: …...
C++ | Leetcode C++题解之第454题四数相加II
题目: 题解: class Solution { public:int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {unordered_map<int, int> countAB;for (int u: A) {for (int v: B) {count…...
【从零开始实现stm32无刷电机FOC】【实践】【7.2/7 完整代码编写】
目录 stm32cubemx配置芯片选择工程配置stm32基础配置SPI的配置定时器的配置ADC的配置中断优先级的配置生成工程 工程代码编写FOC代码结构搭建电机编码器角度读取PWM产生FOC开环代码编写确定电机正负旋转方向电机旋转速度计算多圈逻辑角度电流采样极对数转子角度确定 闭环控制控…...
谷歌收录查询工具,谷歌收录查询工具的使用指南
谷歌收录查询工具是网站管理员和SEO专业人士用于检查网站是否被谷歌搜索引擎收录及其收录情况的重要辅助手段。以下是一些常用的谷歌收录查询工具及其详细使用指南: 一、Google Search Console(谷歌搜索控制台) 简介: Google Sea…...
vue3 拖拽插件(drag)
前端vue项目中,经常会有弹框拖拽的需求,下面介绍常用方法: 1.如果你使用的是elementPlus插件的el-dialog组件,只需要增加draggable属性即可,代码如下: <el-dialogv-model"showDiloag"width"500&quo…...
数据结构--线性表(顺序结构)
1.线性表的定义和基本操作 1.1线性表以及基本逻辑 1.1.1线性表 (1)n(>0)个数据元素的有限序列,记作(a1,a2,...an),其中ai是线性表中的数据元素,n是表的长度。 (2)…...
面试准备111
Java基础 反射 集合 多线程 Synchronized/volatile 线程池 cas atomic 网络 tcp 三次握手/四次挥手 流量控制 拥塞控制 数据结构 算法 Spring 循环依赖 Mybatis 如何防止sql注入 Mysql 索引 索引分类 索引设计原则 事务 四种隔离级别 MVCC 日志 Binlog…...
Spring 的 IOC 和 AOP 是什么,有哪些优点?解密 Spring两大核心概念:IOC与AOP的魅力所在
在现代Java开发中,Spring框架几乎是不可或缺的存在。它不仅简化了开发过程,还提高了软件的灵活性和可维护性。今天,我们要深入探讨Spring中的两个核心概念:IOC(控制反转)和AOP(面向切面编程&…...
第二百六十四节 JPA教程 - JPA查询日期参数示例
JPA教程 - JPA查询日期参数示例 我们可以在查询中使用日期类型值。 以下代码使用EntityManager创建具有两个参数的查询。 然后它传递两个日期类型值。 em.createQuery("SELECT e " "FROM Professor e " "WHERE e.startDate BETWEEN :start AND :en…...
Spring MVC的运行流程详解
Spring MVC作为一个广泛使用的框架,提供了灵活且强大的MVC架构支持。尤其在业务系统中,Spring MVC能够有效地处理大量并发请求,提供良好的用户体验。本文将详细讲解Spring MVC的运行流程,以电商交易系统为案例,帮助读者…...
判断有向图是否为单连通图的算法
判断有向图是否为单连通图的算法 算法描述伪代码C语言实现解释在图论中,单连通图(singly connected graph)是指对于图中的任意两个顶点 m 和 v,如果存在从 m 到 v 的路径,则该路径是唯一的。为了判断一个有向图是否为单连通图,我们需要确保从任意顶点出发,到任意其他顶点…...
php与python建站的区别有哪些
php与Python建站的区别: 1、语言层面Python的特性比php好,更加规范。 2、Python的性能比php高。 3、有只需要启动服务的时候执行一次的代码,在php里每个请求都会被执行一次,Python不需要。虽然php可以通过缓存缩短这方面的差距…...
模型评估与验证:确保模型在未知数据上的表现----示例:使用K折交叉验证评估分类模型、房价预测问题使用K折交叉验证来评估一个线性回归模型的性能
模型评估与验证是机器学习流程中的关键步骤,它帮助我们了解模型在未见过的数据上的泛化能力。交叉验证(Cross-Validation, CV)是一种常用的技术,通过将数据集划分为多个子集并进行多次训练和测试来估计模型的性能。此外࿰…...
awd基础学习
一、常用防御手段 1、改ssh密码 passwd [user] 2、改数据库密码 进入数据库 mysql -uroot -proot 改密码 update mysql.user set passwordpassword(新密码) where userroot; 查看用户信息密码 select host,user,password from mysql.user; 改配置文件 (否则会宕机…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
