在我的小iPad应用程序中,我有一个使用观察者的"切换语言"功能.每个视图控制器在其期间向我的观察者注册viewDidLoad:
.
- (void)viewDidLoad
{
[super viewDidLoad];
[observer registerObject:self];
}
Run Code Online (Sandbox Code Playgroud)
当用户点击"更改语言"按钮时,新语言将存储在我的模型中,并通知观察者并updateUi:
在其注册对象上调用选择器.
这非常有效,除了我在TabBarController中有视图控制器.这是因为当标签栏加载时,它会从其子控制器中获取选项卡图标而不初始化视图,因此viewDidLoad:
不会调用,因此这些视图控制器不会收到语言更改通知.因此,我将registerObject:
调用移到了init
方法中.
回来我viewDidLoad:
以前和我的观察员一起注册时,我常常viewDidUnload:
取消注册.由于我现在正在注册init
,因此取消注册是很有意义的dealloc
.
但这是我的问题.我写的时候:
- (void) dealloc
{
[observer unregisterObject:self];
[super dealloc];
}
Run Code Online (Sandbox Code Playgroud)
我收到此错误:
ARC禁止发送'dealloc'的显式消息
因为我需要打电话[super dealloc]
来确保超级班级正常清理,但ARC禁止这样做,我现在卡住了.当我的物体死亡时,还有另一种获取信息的方法吗?
我想在视图控制器的生命周期结束时执行一些清理,即删除NSNotificationCenter
通知.dealloc
在Swift编译器错误中实现结果:
Cannot override 'dealloc' which has been marked unavailable
Run Code Online (Sandbox Code Playgroud)
在Swift中对象生命结束时执行某些清理的首选方法是什么?
我现在从几个来源(stackoverflow.com,cocoa-dev,文档,博客等)中听到,在init和dealloc方法中使用访问器和设置(foo,setFoo :)是"错误的".据我所知,如果你这样做,很可能会混淆其他正在观察财产的物体.(这里给出一个简单的例子)
但是,由于以下原因,我不得不说我不同意这种做法:
新的Objective-C运行时(iPhone上的那个和10.5中的64位运行时)允许您在不声明相应的ivar的情况下声明属性.例如,以下类将在10.5或iPhone(设备,而不是模拟器)上编译得很好:
@interface Foo : NSObject { }
@property (retain) id someObject;
@end
@implementation Foo
@synthesize someObject;
@end
Run Code Online (Sandbox Code Playgroud)
理解上面是一个完全有效的Objective-C类,假设我决定编写一个初始化程序,并且出于内存管理的目的,使用dealloc方法(因为在iPhone上没有GC).我读过有关初始化器和释放器的所有内容都会让我编写以下两种方法:
- (id) init {
if (self = [super init]) {
//initialize the value of someObject to nil
[self setSomeObject:nil];
}
return self;
}
- (void) dealloc {
//setting someObject to nil will release the previous value
[self setSomeObject:nil];
[super dealloc];
}
Run Code Online (Sandbox Code Playgroud)
但是,根据文件和流行的观点,这是"错误的".所以我的问题是这样的:
如果其中任何一个的答案是"你不能",那么在init和dealloc方法中使用访问器怎么可能不好?
想知道有经验的人是否可以解释这一点.我见过......的例子
[view release];
view = nil;
Run Code Online (Sandbox Code Playgroud)
....在(void)dealloc里面.
有什么区别,哪一个比另一个更好?什么是最好的方法?
在进行retainCount测试时,我个人已经看到nil为我减少了3到0的计数,但是只发布从3减少到2.
int main(){
Employee *e = new Employee();
delete e;
delete e;
...
delete e;
return 0;
}
Run Code Online (Sandbox Code Playgroud) 在Clang的Objective-C自动参考计数中,我们看到以下内容
对于__weak对象,左值更新为指向新的指针,除非新指针是当前正在进行解除分配的对象,在这种情况下,左值更新为空指针.这必须相对于对象的其他赋值,从对象读取以及新指针的最终版本以原子方式执行.
在objc-weak.mm中,我们看到以下代码块weak_register_no_lock()
:
if (deallocating) {
if (crashIfDeallocating) {
_objc_fatal("Cannot form weak reference to instance (%p) of "
"class %s. It is possible that this object was "
"over-released, or is in the process of deallocation.",
(void*)referent, object_getClassName((id)referent));
} else {
return nil;
}
}
Run Code Online (Sandbox Code Playgroud)
我在我的UIViewController子类dealloc
方法中设置了一个断点,并尝试[self allowsWeakReference]
在lldb中调用,从而产生了NO
值.
如果我们尝试将self设置为另一个对象的weak属性,则应用程序将根据objc-weak.mm代码崩溃.
问题是 - 为什么会发生这种情况?铿锵的规格是错的吗?这是objc实现中的一个错误吗?
这是一段简单的代码,可以重现崩溃:
//cc -fmodules -fobjc-arc -g crash.m -o crash
@import Foundation;
@interface Foo : NSObject
@end
@implementation Foo …
Run Code Online (Sandbox Code Playgroud) weak-references objective-c clang dealloc automatic-ref-counting
在我的init方法中使用点表示法将retain属性初始化为nil是不是一个坏主意?
对于像这样的普通房产:
@property (nonatomic, retain) id foo;
Run Code Online (Sandbox Code Playgroud)
在我设置的init方法中说self.foo = nil
.合成的方法首先释放或自动释放foo
(不完全确定潜在的实施).被foo
guaranted第一setter或getter调用之前是零?或者它会指向随机垃圾,除非我明确设置foo = nil
没有点符号?
initialization properties reference-counting objective-c dealloc
在第二次显示弹出控制器时(在解除它然后重新显示它之后),我收到以下错误:
因未捕获的异常'NSGenericException'而终止应用程序,原因:' - [UIPopoverController dealloc]到达,而popover仍然可见.
堆栈跟踪只是一堆十六进制,SIGABRT每次都发生在UIApplicationMain.这是按钮触发的代码:
- (IBAction)createNewScore:(id)sender {
if (self.pc)
if (self.pc.popoverVisible)
return;
else
// Breakpoint is hit here—crashes after this line
[self.pc presentPopoverFromBarButtonItem:(UIBarButtonItem *)sender permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
NGDocumentInfoViewController *documentInfoVC = [[NGDocumentInfoViewController alloc] initWithBlankDocumentTargetInManagedObjectContext:self.context];
UINavigationController *navc = [[UINavigationController alloc] initWithRootViewController:documentInfoVC];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneCreatingNewScore:)];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelCreatingNewScore:)];
navc.navigationBar.topItem.leftBarButtonItem = doneButton;
navc.navigationBar.topItem.rightBarButtonItem = cancelButton;
CGSize popoverSize = CGSizeMake(documentInfoVC.view.bounds.size.width, documentInfoVC.view.bounds.size.height);
documentInfoVC.contentSizeForViewInPopover = popoverSize;
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:navc];
popover.delegate = self;
self.pc …
Run Code Online (Sandbox Code Playgroud) memory-management dealloc uipopovercontroller ios automatic-ref-counting
查看各种Apple示例(例如" 添加音乐"),其中我看到它们将观察者添加到默认值NSNotificationCenter
中viewDidLoad
,然后将其删除dealloc
.这看起来很危险,viewDidLoad
可以多次dealloc
调用而不需要调用.然后,这将多次添加相同的观察者,导致多次调用处理程序.
解决这个问题的方法是删除观察者viewDidUnload
,但这意味着同一个观察者可能会被移除第二次,dealloc
这似乎是一个潜在的问题.
我错过了什么?
例如,如果我要编写此代码:
var t = time_t()
time(&t)
let x = localtime(&t) // returns UnsafeMutablePointer<tm>
println("\(x.memory.tm_hour): \(x.memory.tm_min): \(x.memory.tm_sec)")
Run Code Online (Sandbox Code Playgroud)
......是否还需要做以下事情?
x.destroy()
x.dealloc(1)
Run Code Online (Sandbox Code Playgroud)
或者我们没有分配内存,因此不需要解雇它?
如果我们想象一个函数返回一个UnsafeMutablePointer
:
func point() -> UnsafeMutablePointer<String> {
let a = UnsafeMutablePointer<String>.alloc(1)
a.initialize("Hello, world!")
return a
}
Run Code Online (Sandbox Code Playgroud)
调用此函数将导致指向一个永远不会被销毁的对象的指针,除非我们自己做脏工作.
我在这里问的问题是:从一个localtime()
呼叫收到的指针有什么不同吗?
模拟器和操场都使我们能够向dealloc(1)
返回的指针发送一个调用,但是我们应该这样做还是稍后通过其他方法对返回的指针进行解除分配?
目前我错误地认为我们确实需要销毁和释放.
最后的假设是错误的.我不需要发布,因为我没有创建对象.
我在Apple dev论坛上收到了相同查询的一些答案.
一般来说,你的问题的答案是肯定的.如果你收到一个指向你将负责在C中释放的内存的指针,那么你仍然有责任在从swift调用时释放它... [但]在这种特殊情况下你不需要做任何事情.(JQ)
例程本身为结果维护静态内存,您不需要释放它们.(如果你这样做可能会是一件"坏事")...一般来说,你不知道是否需要释放UnsafePointer所指向的东西....它取决于指针获取其值的位置.(ST)
UnsafePointer的dealloc()与free()不兼容.将alloc()与dealloc()和malloc和co配对.用free().如前所述,您正在调用的函数应该告诉您是否是您对释放结果的响应...只有在指针引用的内存中有非平凡的内容*时才需要destroy(),例如强引用或Swift结构或枚举.一般来说,如果它来自C,你可能不需要销毁()它.(事实上,你可能不应该销毁()它,因为它没有被Swift初始化.)......*"非平凡的内容"并不是官方的Swift术语.我正在使用类比C++概念"平凡可复制"(虽然不一定是"微不足道").(STE)
我现在写了一篇博客文章,概述了关于发布不安全指针的发现和假设,这些指针从StackOverflow,Apple Dev论坛,Twitter和Apple关于分配内存和释放它的旧文档(ARC之前)获取信息.看到这里.
dealloc ×10
objective-c ×5
ios ×3
allocation ×2
properties ×2
swift ×2
accessor ×1
addobserver ×1
c++ ×1
clang ×1
destroy ×1
iphone ×1
memory ×1
pointers ×1
xcode ×1